<script setup lang="ts">
import { computed, onMounted, reactive, shallowRef } from 'vue'
import { ElMessage } from 'element-plus'
import VChart from 'vue-echarts'
import { use } from 'echarts/core'
import { BarChart, LineChart, PieChart } from 'echarts/charts'
import { GridComponent, LegendComponent, TooltipComponent } from 'echarts/components'
import { CanvasRenderer } from 'echarts/renderers'
import {
  exportReport,
  fetchClassRanking,
  fetchMastery,
  fetchQuestionErrors,
  fetchReportBankDetail,
  fetchReportInsights,
  fetchReportOptions,
  fetchReportOverview,
  fetchReportStudentDetail,
  fetchReportStudents,
  fetchReportTrends,
} from '@/api/admin'
import type {
  PageMeta,
  ReportBankDetail,
  ReportDimension,
  ReportFilters,
  ReportInsights,
  ReportMastery,
  ReportOptions,
  ReportOverview,
  ReportQuestionError,
  ReportStudent,
  ReportStudentDetail,
  ReportTrend,
} from '@/types/api'

use([CanvasRenderer, LineChart, BarChart, PieChart, GridComponent, TooltipComponent, LegendComponent])

type ClassRanking = ReportDimension & { members_count: number; attempts: number; completion_rate: number }

const today = new Date()
const weekStart = new Date()
weekStart.setDate(today.getDate() - 6)

const filters = reactive({
  dateRange: [formatDate(weekStart), formatDate(today)] as [string, string],
  class_id: undefined as number | undefined,
  user_id: undefined as number | undefined,
  question_bank_id: undefined as number | undefined,
  category_id: undefined as number | undefined,
  tag_id: undefined as number | undefined,
  type: undefined as string | undefined,
  mode: undefined as string | undefined,
})

const loading = shallowRef(false)
const options = shallowRef<ReportOptions>({ banks: [], classes: [], students: [], categories: [], tags: [] })
const overview = shallowRef<ReportOverview>(emptyOverview())
const trends = shallowRef<ReportTrend[]>([])
const mastery = shallowRef<ReportMastery>({ banks: [], categories: [], types: [], tags: [] })
const ranking = shallowRef<ClassRanking[]>([])
const insights = shallowRef<ReportInsights>({ students: [], questions: [], categories: [] })
const students = shallowRef<ReportStudent[]>([])
const studentMeta = shallowRef<PageMeta>(emptyMeta())
const studentPage = shallowRef(1)
const studentPageSize = shallowRef(10)
const questionErrors = shallowRef<ReportQuestionError[]>([])
const questionMeta = shallowRef<PageMeta>(emptyMeta())
const questionPage = shallowRef(1)
const questionPageSize = shallowRef(10)
const detailVisible = shallowRef(false)
const detailTitle = shallowRef('')
const studentDetail = shallowRef<ReportStudentDetail | null>(null)
const bankDetail = shallowRef<ReportBankDetail | null>(null)

const typeOptions = [
  { label: '单选', value: 'single' },
  { label: '多选', value: 'multiple' },
  { label: '判断', value: 'judge' },
  { label: '填空', value: 'blank' },
]
const modeOptions = [
  { label: '顺序背题', value: 'memorize' },
  { label: '顺序刷题', value: 'sequence' },
  { label: '随机刷题', value: 'random' },
  { label: '错题回顾', value: 'wrong_practice' },
  { label: '整卷测试', value: 'paper' },
]
const statCards = computed(() => [
  { label: '学生数', value: overview.value.students, suffix: '人' },
  { label: '活跃学生', value: overview.value.active_students, suffix: '人' },
  { label: '练习次数', value: overview.value.attempts, suffix: '次' },
  { label: '已作答', value: overview.value.answered_count, suffix: '题' },
  { label: '正确率', value: overview.value.accuracy, suffix: '%' },
  { label: '完成率', value: overview.value.completion_rate, suffix: '%' },
  { label: '平均耗时', value: overview.value.avg_duration_seconds, suffix: '秒' },
  { label: '当前错题', value: overview.value.wrong_questions, suffix: '题' },
])
const trendOption = computed(() => ({
  tooltip: { trigger: 'axis' },
  legend: { data: ['作答题数', '正确率', '活跃学生'] },
  grid: { left: 42, right: 28, top: 42, bottom: 30 },
  xAxis: { type: 'category', data: trends.value.map((item) => item.day) },
  yAxis: [{ type: 'value' }, { type: 'value', max: 100 }],
  series: [
    { name: '作答题数', type: 'bar', data: trends.value.map((item) => item.answered_count) },
    { name: '正确率', type: 'line', yAxisIndex: 1, smooth: true, data: trends.value.map((item) => item.accuracy) },
    { name: '活跃学生', type: 'line', smooth: true, data: trends.value.map((item) => item.active_students) },
  ],
}))
const bankOption = computed(() => ({
  tooltip: { trigger: 'axis' },
  grid: { left: 42, right: 18, top: 32, bottom: 68 },
  xAxis: { type: 'category', axisLabel: { rotate: 28 }, data: mastery.value.banks.map((item) => item.name) },
  yAxis: { type: 'value', max: 100 },
  series: [{ name: '正确率', type: 'bar', data: mastery.value.banks.map((item) => item.accuracy) }],
}))
const typeOption = computed(() => ({
  tooltip: { trigger: 'item' },
  legend: { bottom: 0 },
  series: [{
    name: '题型作答',
    type: 'pie',
    radius: ['42%', '66%'],
    data: mastery.value.types.map((item) => ({ name: typeLabel(String(item.id)), value: item.answered_count })),
  }],
}))
const weakCategoryOption = computed(() => ({
  tooltip: { trigger: 'axis' },
  grid: { left: 42, right: 18, top: 28, bottom: 80 },
  xAxis: { type: 'category', axisLabel: { rotate: 32 }, data: mastery.value.categories.slice(0, 8).map((item) => item.name) },
  yAxis: { type: 'value', max: 100 },
  series: [{ name: '正确率', type: 'bar', data: mastery.value.categories.slice(0, 8).map((item) => item.accuracy) }],
}))

function formatDate(date: Date) {
  return date.toISOString().slice(0, 10)
}

function emptyOverview(): ReportOverview {
  return {
    students: 0,
    active_students: 0,
    attempts: 0,
    answered_count: 0,
    accuracy: 0,
    completion_rate: 0,
    avg_duration_seconds: 0,
    wrong_questions: 0,
    mastered_wrong_questions: 0,
  }
}

function emptyMeta(): PageMeta {
  return { current_page: 1, per_page: 10, total: 0, last_page: 1 }
}

function params(extra: Partial<ReportFilters> = {}): ReportFilters {
  return {
    date_from: filters.dateRange?.[0],
    date_to: filters.dateRange?.[1],
    class_id: filters.class_id,
    user_id: filters.user_id,
    question_bank_id: filters.question_bank_id,
    category_id: filters.category_id,
    tag_id: filters.tag_id,
    type: filters.type as ReportFilters['type'],
    mode: filters.mode,
    ...extra,
  }
}

function typeLabel(value?: string) {
  return typeOptions.find((item) => item.value === value)?.label ?? value ?? '未知'
}

async function loadOptions() {
  options.value = (await fetchReportOptions(params())).data
}

async function loadAll() {
  loading.value = true
  try {
    await loadOptions()
    const [overviewResponse, trendsResponse, masteryResponse, rankingResponse, insightsResponse] = await Promise.all([
      fetchReportOverview(params()),
      fetchReportTrends(params()),
      fetchMastery(params()),
      fetchClassRanking(params()),
      fetchReportInsights(params()),
    ])
    overview.value = overviewResponse.data
    trends.value = trendsResponse.data
    mastery.value = masteryResponse.data
    ranking.value = rankingResponse.data
    insights.value = insightsResponse.data
    studentPage.value = 1
    questionPage.value = 1
    await Promise.all([loadStudents(), loadQuestionErrors()])
  } finally {
    loading.value = false
  }
}

async function loadStudents() {
  const response = await fetchReportStudents(params({ page: studentPage.value, per_page: studentPageSize.value }))
  students.value = response.data.items
  studentMeta.value = response.data.meta
}

async function loadQuestionErrors() {
  const response = await fetchQuestionErrors(params({ page: questionPage.value, per_page: questionPageSize.value }))
  questionErrors.value = response.data.items
  questionMeta.value = response.data.meta
}

async function changeStudentPage(page: number) {
  studentPage.value = page
  await loadStudents()
}

async function changeStudentPageSize(size: number) {
  studentPageSize.value = size
  studentPage.value = 1
  await loadStudents()
}

async function changeQuestionPage(page: number) {
  questionPage.value = page
  await loadQuestionErrors()
}

async function changeQuestionPageSize(size: number) {
  questionPageSize.value = size
  questionPage.value = 1
  await loadQuestionErrors()
}

async function resetFilters() {
  filters.dateRange = [formatDate(weekStart), formatDate(today)]
  filters.class_id = undefined
  filters.user_id = undefined
  filters.question_bank_id = undefined
  filters.category_id = undefined
  filters.tag_id = undefined
  filters.type = undefined
  filters.mode = undefined
  await loadAll()
}

async function exportData() {
  await exportReport(params())
  ElMessage.success('报表已导出到 storage/app/exports')
}

async function openStudent(row: ReportStudent) {
  studentDetail.value = (await fetchReportStudentDetail(row.id, params())).data
  bankDetail.value = null
  detailTitle.value = `${row.name} 的学习画像`
  detailVisible.value = true
}

async function openBank(row: ReportDimension) {
  if (typeof row.id !== 'number') return
  bankDetail.value = (await fetchReportBankDetail(row.id, params())).data
  studentDetail.value = null
  detailTitle.value = `${row.name} 题库分析`
  detailVisible.value = true
}

onMounted(loadAll)
</script>

<template>
  <section v-loading="loading" class="report-page">
    <div class="toolbar mb-4">
      <div class="flex-1">
        <h1 class="page-title">统计报表</h1>
        <p class="muted text-sm mt-1">按已作答题目统计正确率，未答题只计入完成率。</p>
      </div>
      <ElButton @click="resetFilters">重置</ElButton>
      <ElButton type="primary" @click="exportData">导出报表</ElButton>
    </div>

    <section class="panel report-filter">
      <ElDatePicker v-model="filters.dateRange" type="daterange" value-format="YYYY-MM-DD" start-placeholder="开始日期" end-placeholder="结束日期" />
      <ElSelect v-model="filters.class_id" clearable filterable placeholder="班级">
        <ElOption v-for="item in options.classes" :key="item.id" :label="item.name" :value="item.id" />
      </ElSelect>
      <ElSelect v-model="filters.user_id" clearable filterable placeholder="学生">
        <ElOption v-for="item in options.students" :key="item.id" :label="`${item.name} ${item.email}`" :value="item.id" />
      </ElSelect>
      <ElSelect v-model="filters.question_bank_id" clearable filterable placeholder="题库" @change="loadOptions">
        <ElOption v-for="item in options.banks" :key="item.id" :label="item.name" :value="item.id" />
      </ElSelect>
      <ElSelect v-model="filters.category_id" clearable filterable placeholder="分类">
        <ElOption v-for="item in options.categories" :key="item.id" :label="item.name" :value="item.id" />
      </ElSelect>
      <ElSelect v-model="filters.tag_id" clearable filterable placeholder="标签">
        <ElOption v-for="item in options.tags" :key="item.id" :label="item.name" :value="item.id" />
      </ElSelect>
      <ElSelect v-model="filters.type" clearable placeholder="题型">
        <ElOption v-for="item in typeOptions" :key="item.value" :label="item.label" :value="item.value" />
      </ElSelect>
      <ElSelect v-model="filters.mode" clearable placeholder="模式">
        <ElOption v-for="item in modeOptions" :key="item.value" :label="item.label" :value="item.value" />
      </ElSelect>
      <ElButton type="primary" @click="loadAll">查询</ElButton>
    </section>

    <div class="report-stats">
      <article v-for="item in statCards" :key="item.label" class="stat-card">
        <span>{{ item.label }}</span>
        <strong>{{ item.value }}<small>{{ item.suffix }}</small></strong>
      </article>
    </div>

    <section class="panel p-5 mt-4">
      <div class="section-head">
        <h2 class="page-title">总览趋势</h2>
        <span class="muted text-sm">默认展示近 7 天</span>
      </div>
      <VChart class="trend-chart" :option="trendOption" autoresize />
    </section>

    <section class="report-layout mt-4">
      <div class="panel p-5">
        <h2 class="page-title mb-3">题库分析</h2>
        <VChart class="mastery-chart" :option="bankOption" autoresize />
        <ElTable :data="mastery.banks" row-key="id" class="mt-3" height="260">
          <ElTableColumn prop="name" label="题库" min-width="150" show-overflow-tooltip />
          <ElTableColumn prop="answered_count" label="作答" width="82" />
          <ElTableColumn prop="wrong_count" label="错误" width="82" />
          <ElTableColumn label="正确率" width="92">
            <template #default="{ row }">{{ row.accuracy }}%</template>
          </ElTableColumn>
          <ElTableColumn label="操作" width="86" fixed="right">
            <template #default="{ row }">
              <ElButton link type="primary" @click="openBank(row)">详情</ElButton>
            </template>
          </ElTableColumn>
        </ElTable>
      </div>
      <div class="panel p-5">
        <h2 class="page-title mb-3">题型与薄弱分类</h2>
        <div class="mini-charts">
          <VChart class="mini-chart" :option="typeOption" autoresize />
          <VChart class="mini-chart" :option="weakCategoryOption" autoresize />
        </div>
      </div>
    </section>

    <section class="panel p-5 mt-4">
      <h2 class="page-title mb-3">学生分析</h2>
      <ElTable :data="students" row-key="id">
        <ElTableColumn prop="name" label="学生" min-width="120" show-overflow-tooltip />
        <ElTableColumn prop="email" label="账号" min-width="180" show-overflow-tooltip />
        <ElTableColumn prop="attempts" label="练习" width="82" />
        <ElTableColumn prop="answered_count" label="作答题数" width="100" />
        <ElTableColumn label="正确率" width="92">
          <template #default="{ row }">{{ row.accuracy }}%</template>
        </ElTableColumn>
        <ElTableColumn prop="wrong_questions" label="错题" width="82" />
        <ElTableColumn prop="avg_duration_seconds" label="均耗时(秒)" width="112" />
        <ElTableColumn prop="last_answered_at" label="最近作答" min-width="150" show-overflow-tooltip />
        <ElTableColumn label="操作" width="86" fixed="right">
          <template #default="{ row }">
            <ElButton link type="primary" @click="openStudent(row)">画像</ElButton>
          </template>
        </ElTableColumn>
      </ElTable>
      <ElPagination
        class="report-pagination"
        layout="total, sizes, prev, pager, next"
        :total="studentMeta.total"
        :page-size="studentPageSize"
        :current-page="studentPage"
        :page-sizes="[10, 20, 50]"
        @update:current-page="changeStudentPage"
        @update:page-size="changeStudentPageSize"
      />
    </section>

    <section class="report-layout mt-4">
      <div class="panel p-5">
        <h2 class="page-title mb-3">题目错误排行</h2>
        <ElTable :data="questionErrors" row-key="id" height="420">
          <ElTableColumn prop="content" label="题干" min-width="260" show-overflow-tooltip />
          <ElTableColumn prop="bank_name" label="题库" min-width="120" show-overflow-tooltip />
          <ElTableColumn label="题型" width="80">
            <template #default="{ row }">{{ typeLabel(row.type) }}</template>
          </ElTableColumn>
          <ElTableColumn prop="attempts" label="作答" width="76" />
          <ElTableColumn prop="wrong_count" label="错误" width="76" />
          <ElTableColumn label="错误率" width="92">
            <template #default="{ row }">{{ row.wrong_rate }}%</template>
          </ElTableColumn>
        </ElTable>
        <ElPagination
          class="report-pagination"
          layout="total, sizes, prev, pager, next"
          :total="questionMeta.total"
          :page-size="questionPageSize"
          :current-page="questionPage"
          :page-sizes="[10, 20, 50]"
          @update:current-page="changeQuestionPage"
          @update:page-size="changeQuestionPageSize"
        />
      </div>
      <div class="panel p-5">
        <h2 class="page-title mb-3">重点关注</h2>
        <div class="insight-block">
          <h3>低正确率学生</h3>
          <ElEmpty v-if="insights.students.length === 0" description="暂无需要重点关注的学生" />
          <div v-for="item in insights.students" :key="item.id" class="insight-row">
            <span>{{ item.name }}</span>
            <ElTag type="danger" effect="plain">{{ item.accuracy }}%</ElTag>
          </div>
        </div>
        <div class="insight-block">
          <h3>高频错题</h3>
          <ElEmpty v-if="insights.questions.length === 0" description="暂无高频错题" />
          <div v-for="item in insights.questions" :key="item.id" class="insight-row">
            <span>{{ item.content }}</span>
            <ElTag type="warning" effect="plain">{{ item.wrong_rate }}%</ElTag>
          </div>
        </div>
        <div class="insight-block">
          <h3>薄弱分类</h3>
          <ElEmpty v-if="insights.categories.length === 0" description="暂无明显薄弱分类" />
          <div v-for="item in insights.categories" :key="`${item.bank_name}-${item.id}`" class="insight-row">
            <span>{{ item.bank_name ? `${item.bank_name} / ` : '' }}{{ item.name }}</span>
            <ElTag type="danger" effect="plain">{{ item.accuracy }}%</ElTag>
          </div>
        </div>
      </div>
    </section>

    <ElDrawer v-model="detailVisible" :title="detailTitle" size="min(720px, 100vw)">
      <div v-if="studentDetail" class="detail-stack">
        <div class="report-stats compact">
          <article v-for="item in [
            { label: '作答题数', value: studentDetail.overview.answered_count },
            { label: '正确率', value: `${studentDetail.overview.accuracy}%` },
            { label: '完成率', value: `${studentDetail.overview.completion_rate}%` },
            { label: '当前错题', value: studentDetail.overview.wrong_questions },
          ]" :key="item.label" class="stat-card">
            <span>{{ item.label }}</span>
            <strong>{{ item.value }}</strong>
          </article>
        </div>
        <ElTable :data="studentDetail.banks" row-key="id">
          <ElTableColumn prop="name" label="薄弱题库" min-width="160" />
          <ElTableColumn prop="answered_count" label="作答" width="80" />
          <ElTableColumn label="正确率" width="90">
            <template #default="{ row }">{{ row.accuracy }}%</template>
          </ElTableColumn>
        </ElTable>
        <ElTable :data="studentDetail.question_errors" row-key="id">
          <ElTableColumn prop="content" label="错题" min-width="220" show-overflow-tooltip />
          <ElTableColumn prop="wrong_count" label="错误" width="80" />
          <ElTableColumn label="错误率" width="90">
            <template #default="{ row }">{{ row.wrong_rate }}%</template>
          </ElTableColumn>
        </ElTable>
      </div>
      <div v-if="bankDetail" class="detail-stack">
        <div class="report-stats compact">
          <article v-for="item in [
            { label: '作答题数', value: bankDetail.overview.answered_count },
            { label: '正确率', value: `${bankDetail.overview.accuracy}%` },
            { label: '平均耗时', value: `${bankDetail.overview.avg_duration_seconds}秒` },
            { label: '当前错题', value: bankDetail.overview.wrong_questions },
          ]" :key="item.label" class="stat-card">
            <span>{{ item.label }}</span>
            <strong>{{ item.value }}</strong>
          </article>
        </div>
        <ElTable :data="bankDetail.categories" row-key="id">
          <ElTableColumn prop="name" label="分类" min-width="160" />
          <ElTableColumn prop="answered_count" label="作答" width="80" />
          <ElTableColumn prop="wrong_count" label="错误" width="80" />
          <ElTableColumn label="正确率" width="90">
            <template #default="{ row }">{{ row.accuracy }}%</template>
          </ElTableColumn>
        </ElTable>
        <ElTable :data="bankDetail.question_errors" row-key="id">
          <ElTableColumn prop="content" label="高错题目" min-width="220" show-overflow-tooltip />
          <ElTableColumn prop="wrong_count" label="错误" width="80" />
          <ElTableColumn label="错误率" width="90">
            <template #default="{ row }">{{ row.wrong_rate }}%</template>
          </ElTableColumn>
        </ElTable>
      </div>
    </ElDrawer>
  </section>
</template>

<style scoped>
.report-page {
  display: flex;
  flex-direction: column;
  gap: 0;
}

.report-filter {
  display: grid;
  grid-template-columns: minmax(240px, 1.4fr) repeat(4, minmax(140px, 1fr)) auto;
  gap: 12px;
  padding: 16px;
  align-items: center;
}

.report-filter :deep(.el-date-editor),
.report-filter :deep(.el-select) {
  width: 100%;
}

.report-stats {
  display: grid;
  grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
  gap: 12px;
  margin-top: 16px;
}

.report-stats.compact {
  margin-top: 0;
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.stat-card {
  padding: 16px;
  border: 1px solid var(--qq-line);
  border-radius: 8px;
  background: white;
}

.stat-card span {
  display: block;
  color: var(--qq-muted);
  font-size: 13px;
}

.stat-card strong {
  display: block;
  margin-top: 8px;
  font-size: 24px;
  line-height: 1.1;
}

.stat-card small {
  margin-left: 2px;
  font-size: 13px;
  color: var(--qq-muted);
}

.section-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  margin-bottom: 12px;
}

.trend-chart,
.mastery-chart {
  width: 100%;
  height: 320px;
}

.report-layout {
  display: grid;
  grid-template-columns: minmax(0, 1.35fr) minmax(360px, 0.85fr);
  gap: 16px;
}

.mini-charts {
  display: grid;
  grid-template-columns: 1fr;
  gap: 16px;
}

.mini-chart {
  width: 100%;
  height: 260px;
}

.report-pagination {
  margin-top: 14px;
  justify-content: flex-end;
}

.insight-block + .insight-block {
  margin-top: 18px;
}

.insight-block h3 {
  margin: 0 0 10px;
  font-size: 15px;
}

.insight-row {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: center;
  padding: 10px 0;
  border-bottom: 1px solid var(--qq-line);
}

.insight-row span {
  min-width: 0;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.detail-stack {
  display: grid;
  gap: 16px;
}

@media (max-width: 1100px) {
  .report-filter {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .report-layout {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 640px) {
  .toolbar {
    align-items: stretch;
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
  }

  .toolbar .flex-1 {
    grid-column: 1 / -1;
  }

  .report-filter {
    grid-template-columns: 1fr;
    padding: 12px;
  }

  .section-head {
    align-items: flex-start;
    flex-direction: column;
  }

  .report-stats {
    grid-template-columns: repeat(2, minmax(0, 1fr));
    gap: 10px;
  }

  .report-stats.compact {
    grid-template-columns: 1fr;
  }

  .stat-card {
    padding: 12px;
  }

  .stat-card strong {
    font-size: 20px;
  }

  .trend-chart,
  .mastery-chart,
  .mini-chart {
    height: 240px;
  }

  .report-layout {
    gap: 12px;
  }

  .panel {
    padding: 12px !important;
  }

  .report-pagination {
    justify-content: flex-start;
    overflow-x: auto;
    padding-bottom: 4px;
  }

  .insight-row {
    align-items: flex-start;
    flex-direction: column;
    gap: 6px;
  }

  .insight-row span {
    white-space: normal;
  }
}
</style>
