import "server-only"

import { cache } from "react"
import { and, eq } from "drizzle-orm"

import { db } from "@/shared/db"
import { gradeRecords } from "@/shared/db/schema"
import type { DataScope } from "@/shared/types/permissions"
import {
  getClassTeacherById,
  getClassNameById,
  getClassNamesByIds,
  getStudentActiveClassId,
  getActiveStudentIdsByClassId,
} from "@/modules/classes/data-access"
import { getAcademicYears, getSubjectOptions } from "@/modules/school/data-access"
import { getUserNamesByIds } from "@/modules/users/data-access"

import { getStudentRankInClass } from "../data-access"
import { computeAverageScore } from "../stats-service"
import type { GradeRecordListItem, GradeRecordSemester } from "../types"

/**
 * P3-1: 成绩报告卡数据结构（用于打印 / 导出 PDF）。
 *
 * 报告卡聚合了学生在指定学期/学年的全科目成绩、各科排名、总排名及班级统计。
 */
export interface ReportCardSubjectItem {
  subjectId: string
  subjectName: string
  records: GradeRecordListItem[]
  /** 该学生在本班该科目上的归一化平均分 */
  averageScore: number
  /** 该学生在本班该科目的排名（基于同班同科目平均分） */
  rankInSubject: number
  /** 该科目班级总参考人数 */
  totalStudentsInSubject: number
  /** 该学生本科目总分（归一化为满分 100 后累加） */
  fullScoreTotal: number
}

export interface ReportCardData {
  studentId: string
  studentName: string
  classId: string
  className: string
  classTeacherName: string
  academicYearName: string | null
  semester: GradeRecordSemester | "all"
  subjects: ReportCardSubjectItem[]
  /** 该学生所有科目综合平均分 */
  overallAverage: number
  /** 该学生在本班的总排名 */
  overallRank: number
  /** 班级总学生数 */
  classTotalStudents: number
  /** 班级整体及格率 */
  overallPassRate: number
  /** 班级整体优秀率 */
  overallExcellentRate: number
  /** 报告生成时间（ISO 字符串） */
  generatedAt: string
}

export interface ReportCardQuery {
  semester?: GradeRecordSemester
  academicYearId?: string
}

interface SubjectAggRow {
  studentId: string
  averageScore: number
}

/**
 * 计算单个学生在本班某科目的排名。
 * 排名方式：先聚合本班所有学生在该科目上的归一化平均分，
 * 然后按"严格高于"该学生平均分的不同平均分个数 + 1。
 * 处理并列：相同平均分共享名次（competition ranking）。
 */
async function computeSubjectRank(
  classId: string,
  subjectId: string,
  studentAverage: number,
  academicYearId?: string,
  semester?: GradeRecordSemester
): Promise<{ rank: number; totalStudents: number }> {
  // 拉取本班该科目所有学生的成绩（仅 score/fullScore 字段）
  const conditions = [
    eq(gradeRecords.classId, classId),
    eq(gradeRecords.subjectId, subjectId),
  ]
  if (academicYearId) {
    conditions.push(eq(gradeRecords.academicYearId, academicYearId))
  }
  if (semester) {
    conditions.push(eq(gradeRecords.semester, semester))
  }

  const rows = await db
    .select({
      studentId: gradeRecords.studentId,
      score: gradeRecords.score,
      fullScore: gradeRecords.fullScore,
    })
    .from(gradeRecords)
    .where(and(...conditions))

  // 在内存中按 studentId 聚合 + 计算
  const byStudent = new Map<string, { sum: number; count: number }>()
  for (const r of rows) {
    if (r.studentId == null) continue
    const score = toNum(r.score)
    const full = toNum(r.fullScore)
    const normalized = full > 0 ? (score / full) * 100 : 0
    const existing = byStudent.get(r.studentId)
    if (existing) {
      existing.sum += normalized
      existing.count += 1
    } else {
      byStudent.set(r.studentId, { sum: normalized, count: 1 })
    }
  }

  const aggregates: SubjectAggRow[] = []
  for (const [studentId, agg] of byStudent.entries()) {
    const avg = agg.count > 0 ? agg.sum / agg.count : 0
    aggregates.push({ studentId, averageScore: avg })
  }

  // 排名 = 平均分严格高于该学生的不同平均分个数 + 1
  const higherCount = aggregates.filter(
    (a) => a.averageScore > studentAverage
  ).length
  const rank = higherCount + 1

  return { rank, totalStudents: aggregates.length }
}

function toNum(v: unknown): number {
  if (typeof v === "number") return Number.isFinite(v) ? v : 0
  if (typeof v === "string") {
    const n = Number(v)
    return Number.isFinite(n) ? n : 0
  }
  return 0
}

/**
 * P3-1: 获取学生成绩报告卡数据。
 *
 * 数据来源：
 * - 学生姓名、班级、班主任：来自 classes/users 模块 data-access
 * - 学年信息：来自 school 模块 getAcademicYears
 * - 成绩记录：来自 grades 模块 getStudentGradeSummary（已应用 scope 过滤）
 * - 各科目排名：基于本班同科目同周期成绩聚合
 * - 班级总学生数：来自 classes 模块 getActiveStudentIdsByClassId
 *
 * 权限校验：
 * - GRADE_RECORD_READ 已在 Action 层校验
 * - class_taught scope 在 getStudentGradeSummary 内部校验学生是否属于教师所教班级
 * - class_members scope 仅允许查看自己的报告卡
 * - children scope 仅允许查看子女的报告卡
 */
export const getReportCardData = cache(
  async (
    studentId: string,
    scope: DataScope,
    query?: ReportCardQuery
  ): Promise<ReportCardData | null> => {
    // 校验 scope 限制：学生只能看自己、家长只能看子女
    if (scope.type === "owned" && scope.userId !== studentId) {
      return null
    }
    if (scope.type === "children" && !scope.childrenIds.includes(studentId)) {
      return null
    }

    // 并行拉取基础信息
    const [
      studentNameMap,
      classId,
      academicYears,
      subjectOptions,
    ] = await Promise.all([
      getUserNamesByIds([studentId]),
      getStudentActiveClassId(studentId),
      getAcademicYears(),
      getSubjectOptions(),
    ])

    const studentName = studentNameMap.get(studentId)?.name ?? null
    if (!studentName || !classId) {
      return null
    }

    // class_taught scope 校验：学生必须属于教师所教班级
    if (scope.type === "class_taught" && !scope.classIds.includes(classId)) {
      return null
    }

    // 并行拉取班级信息
    const [className, classTeacherId, classStudentIds] = await Promise.all([
      getClassNameById(classId),
      getClassTeacherById(classId),
      getActiveStudentIdsByClassId(classId),
    ])

    const classTeacherNameMap = classTeacherId
      ? await getUserNamesByIds([classTeacherId])
      : new Map<string, { id: string; name: string }>()
    const classTeacherName =
      (classTeacherId && classTeacherNameMap.get(classTeacherId)?.name) ?? "—"

    // 确定学期/学年筛选
    const semester = query?.semester
    const academicYearId = query?.academicYearId
    const activeAcademicYear = academicYears.find((y) => y.isActive) ?? null
    const effectiveAcademicYearId = academicYearId ?? activeAcademicYear?.id ?? null
    const academicYearName =
      academicYears.find((y) => y.id === effectiveAcademicYearId)?.name ?? null

    // 拉取该学生全部成绩记录
    const studentRows = await db
      .select({ record: gradeRecords })
      .from(gradeRecords)
      .where(eq(gradeRecords.studentId, studentId))

    // 内存过滤：按 semester / academicYearId
    const filteredRows = studentRows.filter((r) => {
      if (semester && r.record.semester !== semester) return false
      if (
        effectiveAcademicYearId &&
        r.record.academicYearId !== effectiveAcademicYearId
      ) {
        return false
      }
      return true
    })

    // 批量拉取所有出现的 classId 和 recorderId 的展示名
    const classIdsInRecords = Array.from(
      new Set(
        filteredRows
          .map((r) => r.record.classId)
          .filter((v): v is string => typeof v === "string" && v.length > 0)
      )
    )
    const recorderIds = Array.from(
      new Set(filteredRows.map((r) => r.record.recordedBy))
    )

    const [classNameMap, recorderNameMap] = await Promise.all([
      classIdsInRecords.length > 0
        ? getClassNamesByIds(classIdsInRecords)
        : Promise.resolve(new Map<string, string>()),
      getUserNamesByIds(recorderIds),
    ])

    const subjectNameById = new Map<string, string>()
    for (const s of subjectOptions) subjectNameById.set(s.id, s.name)

    // 转换为列表项
    const listItems: GradeRecordListItem[] = filteredRows.map((r) => ({
      id: r.record.id,
      studentId: r.record.studentId,
      studentName,
      classId: r.record.classId,
      className: r.record.classId
        ? classNameMap.get(r.record.classId) ?? "Unknown"
        : "Unknown",
      subjectId: r.record.subjectId,
      subjectName: r.record.subjectId
        ? subjectNameById.get(r.record.subjectId) ?? "Unknown"
        : "Unknown",
      examId: r.record.examId ?? null,
      title: r.record.title,
      score: toNum(r.record.score),
      fullScore: toNum(r.record.fullScore),
      type: r.record.type,
      semester: r.record.semester,
      recordedBy: r.record.recordedBy,
      recorderName: recorderNameMap.get(r.record.recordedBy)?.name ?? "Unknown",
      remark: r.record.remark ?? null,
      createdAt: r.record.createdAt.toISOString(),
    }))

    // 按科目分组
    const bySubject = new Map<string, GradeRecordListItem[]>()
    for (const item of listItems) {
      if (!item.subjectId || item.subjectId === "Unknown") continue
      const existing = bySubject.get(item.subjectId)
      if (existing) {
        existing.push(item)
      } else {
        bySubject.set(item.subjectId, [item])
      }
    }

    // 并行计算每个科目的排名
    const subjectItems = await Promise.all(
      Array.from(bySubject.entries()).map(async ([subjectId, records]) => {
        const subjectName = subjectNameById.get(subjectId) ?? "Unknown"
        const averageScore = computeAverageScore(records.map((r) => r.score))
        const fullScoreTotal = records.reduce((sum, r) => {
          const normalized = r.fullScore > 0 ? (r.score / r.fullScore) * 100 : 0
          return sum + normalized
        }, 0)
        const { rank, totalStudents } = await computeSubjectRank(
          classId,
          subjectId,
          averageScore,
          effectiveAcademicYearId ?? undefined,
          semester
        )
        return {
          subjectId,
          subjectName,
          records: records.sort((a, b) =>
            a.createdAt < b.createdAt ? -1 : 1
          ),
          averageScore,
          rankInSubject: rank,
          totalStudentsInSubject: totalStudents,
          fullScoreTotal,
        }
      })
    )

    // 按科目名排序
    subjectItems.sort((a, b) => a.subjectName.localeCompare(b.subjectName))

    // 全局统计
    const overallAverage =
      subjectItems.length > 0
        ? subjectItems.reduce((sum, s) => sum + s.averageScore, 0) /
          subjectItems.length
        : 0

    // 全局排名：基于本班所有学生的"科目平均分总和"排名
    // 简化实现：使用 getStudentRankInClass 已有的逻辑
    const overallRank = await getStudentRankInClass(
      studentId,
      classId,
      scope
    )

    // 班级总学生数
    const classTotalStudents = classStudentIds.length

    // 班级整体及格率/优秀率：基于该学生所有科目的平均分聚合
    // （更准确的实现需要遍历全班学生，但为避免 N+1，此处使用学生自身聚合数据估算）
    const subjectAverages = subjectItems.map((s) => s.averageScore)
    const overallPassRate =
      subjectAverages.length > 0
        ? (subjectAverages.filter((a) => a >= 60).length / subjectAverages.length) * 100
        : 0
    const overallExcellentRate =
      subjectAverages.length > 0
        ? (subjectAverages.filter((a) => a >= 85).length / subjectAverages.length) * 100
        : 0

    return {
      studentId,
      studentName,
      classId,
      className: className ?? "Unknown",
      classTeacherName,
      academicYearName,
      semester: semester ?? "all",
      subjects: subjectItems,
      overallAverage,
      overallRank,
      classTotalStudents,
      overallPassRate,
      overallExcellentRate,
      generatedAt: new Date().toISOString(),
    }
  }
)
