import "server-only"

import { cache } from "react"
import { and, asc, eq, inArray, isNotNull, ne } from "drizzle-orm"

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

import { normalize, toNumber } from "./lib/grade-utils"
import { buildScopeClassFilter } from "./lib/scope-filter"
import {
  buildGradeTrendPoints,
  buildGrowthArchivePoints,
  computeAverageScore,
  computeClassComparisonStats,
  computeGradeDistribution,
  computeGradeStats,
  computeSignificance,
  computeSubjectComparisonStats,
  computeTrendAverage,
  findBucketIndex,
} from "./stats-service"
import type {
  ClassComparisonItem,
  ClassComparisonResult,
  ClassComparisonSignificance,
  GradeDistributionByGradeResult,
  GradeDistributionResult,
  GradeDistributionWithPosition,
  GradeTrendResult,
  SchoolWideGradeSummary,
  SchoolWideGradeSummaryItem,
  StudentGrowthArchiveResult,
  SubjectComparisonItem,
} from "./types"

export interface GradeTrendParams {
  classId: string
  subjectId?: string
  studentId?: string
  semester?: "1" | "2"
  examId?: string
  scope: DataScope
  currentUserId?: string
}

export const getGradeTrend = cache(
  async (params: GradeTrendParams): Promise<GradeTrendResult | null> => {
    const conditions = [eq(gradeRecords.classId, params.classId)]
    if (params.subjectId) conditions.push(eq(gradeRecords.subjectId, params.subjectId))
    if (params.studentId) conditions.push(eq(gradeRecords.studentId, params.studentId))
    if (params.semester) conditions.push(eq(gradeRecords.semester, params.semester))
    if (params.examId) conditions.push(eq(gradeRecords.examId, params.examId))

    if (params.scope.type === "class_members" && params.currentUserId) {
      conditions.push(eq(gradeRecords.studentId, params.currentUserId))
    }

    const scopeFilter = buildScopeClassFilter(params.scope)
    if (scopeFilter) conditions.push(scopeFilter)

    const rows = await db
      .select({
        record: gradeRecords,
      })
      .from(gradeRecords)
      .where(and(...conditions))
      .orderBy(asc(gradeRecords.createdAt))

    if (rows.length === 0) return null

    // Fetch display names via cross-module interfaces
    const className = await getClassNameById(params.classId)
    let subjectName = "All Subjects"
    if (params.subjectId) {
      const subjectOptions = await getSubjectOptions()
      const subject = subjectOptions.find((s) => s.id === params.subjectId)
      subjectName = subject?.name ?? "Unknown"
    }

    const points = buildGradeTrendPoints(rows)
    const avg = computeTrendAverage(points)
    const finalClassName = className ?? "Class"
    const studentLabel = params.studentId
      ? `Student ${params.studentId.slice(-4)}`
      : "Class Average"

    return {
      label: params.subjectId
        ? `${finalClassName} · ${subjectName} · ${studentLabel}`
        : `${finalClassName} · ${studentLabel}`,
      points,
      averageScore: avg,
    }
  }
)

export interface ClassComparisonParams {
  gradeId: string
  subjectId: string
  examId?: string
  semester?: "1" | "2"
  scope: DataScope
}

export const getClassComparison = cache(
  async (params: ClassComparisonParams): Promise<ClassComparisonItem[]> => {
    const classRows = await getClassesByGradeId(params.gradeId)

    if (classRows.length === 0) return []

    const scope = params.scope
    const scopeClassIdSet =
      scope.type === "class_taught" ? new Set(scope.classIds) : null
    const allowedClassRows = scopeClassIdSet
      ? classRows.filter((c) => scopeClassIdSet.has(c.id))
      : classRows

    if (allowedClassRows.length === 0) return []

    const allowedClassIds = allowedClassRows.map((c) => c.id)

    // P3 修复：在 SQL where 中使用 inArray 过滤，并通过 buildScopeClassFilter 应用 scope 行级过滤
    const conditions = [
      inArray(gradeRecords.classId, allowedClassIds),
      eq(gradeRecords.subjectId, params.subjectId),
    ]
    if (params.examId) conditions.push(eq(gradeRecords.examId, params.examId))
    if (params.semester) conditions.push(eq(gradeRecords.semester, params.semester))

    const scopeFilter = buildScopeClassFilter(params.scope)
    if (scopeFilter) conditions.push(scopeFilter)

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

    const byClass = new Map<string, typeof allRows>()
    for (const r of allRows) {
      const existing = byClass.get(r.classId)
      if (existing) {
        existing.push(r)
      } else {
        byClass.set(r.classId, [r])
      }
    }

    const result: ClassComparisonItem[] = allowedClassRows.map((cls) => {
      const rows = byClass.get(cls.id) ?? []
      const stats = computeClassComparisonStats(rows)
      return {
        classId: cls.id,
        className: cls.name,
        ...stats,
      }
    })

    return result
  }
)

/**
 * P3-5: 获取班级对比数据 + 班级间统计显著性分析结果。
 *
 * 显著性分析流程：
 * 1. 复用 getClassComparison 获取各班级聚合 stats
 * 2. 找到均分最高与最低班级
 * 3. 从 allRows 中提取这两个班级的归一化分数数组
 * 4. 调用 stats-service.computeSignificance 计算 Cohen's d 与 p 值
 *
 * 返回的 significance 为 null 的场景：
 * - 班级数 < 2
 * - 任意班级样本量 < 2
 * - 方差为 0（所有分数相同）
 *
 * 该函数复用 getClassComparison 的 cache（参数一致），不会触发额外 DB 查询。
 */
export const getClassComparisonWithSignificance = cache(
  async (params: ClassComparisonParams): Promise<ClassComparisonResult> => {
    const items = await getClassComparison(params)

    if (items.length < 2) {
      return { items, significance: null }
    }

    // 找出均分最高与最低班级
    let topClass = items[0]
    let bottomClass = items[0]
    for (const item of items) {
      if (item.averageScore > topClass.averageScore) topClass = item
      if (item.averageScore < bottomClass.averageScore) bottomClass = item
    }

    if (topClass.classId === bottomClass.classId) {
      return { items, significance: null }
    }

    // 重新查询两个班级的原始分数（归一化 0-100），用于统计检验
    const conditions = [
      inArray(gradeRecords.classId, [topClass.classId, bottomClass.classId]),
      eq(gradeRecords.subjectId, params.subjectId),
    ]
    if (params.examId) conditions.push(eq(gradeRecords.examId, params.examId))
    if (params.semester) conditions.push(eq(gradeRecords.semester, params.semester))

    const scopeFilter = buildScopeClassFilter(params.scope)
    if (scopeFilter) conditions.push(scopeFilter)

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

    const topScores: number[] = []
    const bottomScores: number[] = []
    for (const r of rawRows) {
      const normalized = normalize(toNumber(r.score), toNumber(r.fullScore))
      if (r.classId === topClass.classId) topScores.push(normalized)
      else if (r.classId === bottomClass.classId) bottomScores.push(normalized)
    }

    const sigResult = computeSignificance(topScores, bottomScores)
    if (!sigResult) {
      return { items, significance: null }
    }

    const significance: ClassComparisonSignificance = {
      topClassId: topClass.classId,
      bottomClassId: bottomClass.classId,
      cohensD: sigResult.cohensD,
      effectSizeLabel: sigResult.effectSizeLabel,
      pValue: sigResult.pValue,
      isSignificant: sigResult.isSignificant,
    }

    return { items, significance }
  }
)

/**
 * P3-9: 获取学生所在班级的成绩分布 + 学生本人位置标注（隐私保护视图）。
 *
 * 流程：
 * 1. 通过 classes.getStudentActiveClassId 查询学生所在班级
 * 2. 查询该班级所有学生的成绩记录（不含学生 ID，仅聚合计数）
 * 3. 查询该学生最近的归一化分数
 * 4. 调用 stats-service.findBucketIndex 计算学生所在桶索引
 *
 * 返回 null 的场景：
 * - 学生未分配到任何班级
 * - 班级无成绩记录
 *
 * @param studentId - 当前学生 ID
 * @param scope - 当前用户的数据范围（学生为 class_members）
 */
export const getStudentPositionInClassDistribution = cache(
  async (
    studentId: string,
    scope: DataScope
  ): Promise<GradeDistributionWithPosition | null> => {
    // 仅学生（class_members scope）调用，且必须传 studentId
    if (scope.type !== "class_members") return null

    const classId = await getStudentActiveClassId(studentId)
    if (!classId) return null

    const className = (await getClassNameById(classId)) ?? ""

    // 查询该班级全部学生的成绩记录（聚合计数，不含个人身份）
    const conditions = [eq(gradeRecords.classId, classId)]
    const scopeFilter = buildScopeClassFilter(scope)
    if (scopeFilter) conditions.push(scopeFilter)

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

    if (allRows.length === 0) return null

    const distribution = computeGradeDistribution(
      allRows.map((r) => ({ score: r.score, fullScore: r.fullScore }))
    )

    // 获取该学生最近一条成绩记录的归一化分数
    const studentRows = allRows
      .filter((r) => r.studentId === studentId)
      .sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())

    if (studentRows.length === 0) {
      return {
        distribution,
        classId,
        className,
        studentNormalizedScore: null,
        studentBucketIndex: -1,
      }
    }

    const latestRow = studentRows[0]
    const studentNormalizedScore = normalize(
      toNumber(latestRow.score),
      toNumber(latestRow.fullScore)
    )
    const bucketIndex = findBucketIndex(distribution.buckets, studentNormalizedScore)

    return {
      distribution,
      classId,
      className,
      studentNormalizedScore,
      studentBucketIndex: bucketIndex,
    }
  }
)

/**
 * P3-4: 获取学生纵向成长档案（跨学年/学期聚合）。
 *
 * 流程：
 * 1. 校验 class_taught scope（学生必须属于教师所教班级）
 * 2. 获取学生姓名
 * 3. 获取所有学年信息（id → { name, startDate }）
 * 4. 查询学生的全部成绩记录（含 academicYearId）
 * 5. 调用 stats-service.buildGrowthArchivePoints 计算成长点序列
 * 6. 计算总览统计（overallAverage / totalRecords / totalSubjects / totalAcademicYears / growthDelta）
 *
 * 返回 null 的场景：
 * - 学生不存在
 * - 学生无任何成绩记录
 *
 * 注：class_members / children scope 的越权校验由 action 层完成（需 ctx.userId）
 *
 * @param studentId - 学生 ID
 * @param scope - 当前用户的数据范围
 */
export const getStudentGrowthArchive = cache(
  async (
    studentId: string,
    scope: DataScope
  ): Promise<StudentGrowthArchiveResult | null> => {
    // scope 校验：仅 class_taught 需在 data-access 层校验（其余由 action 层处理）
    if (scope.type === "class_taught") {
      const studentClassId = await getStudentActiveClassId(studentId)
      if (studentClassId && !scope.classIds.includes(studentClassId)) {
        return null
      }
    }

    // 获取学生姓名
    const studentNameMap = await getUserNamesByIds([studentId])
    const studentName = studentNameMap.get(studentId)?.name ?? null
    if (!studentName && !studentNameMap.has(studentId)) return null

    // 获取所有学年信息
    const academicYears = await getAcademicYears()
    const academicYearMap = new Map<string, { name: string; startDate: Date }>()
    for (const y of academicYears) {
      academicYearMap.set(y.id, {
        name: y.name,
        startDate: new Date(y.startDate),
      })
    }

    // 查询学生的全部成绩记录（含 academicYearId 非空过滤）
    const conditions = [
      eq(gradeRecords.studentId, studentId),
      isNotNull(gradeRecords.academicYearId),
      ne(gradeRecords.academicYearId, ""),
    ]

    const scopeFilter = buildScopeClassFilter(scope, studentId)
    if (scopeFilter) conditions.push(scopeFilter)

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

    if (rows.length === 0) {
      return null
    }

    // 构建原始数据行（合并学年信息）
    const archiveRows = rows
      .map((r) => {
        const yearId = r.academicYearId
        if (!yearId) return null
        const yearInfo = academicYearMap.get(yearId)
        if (!yearInfo) return null
        return {
          academicYearId: yearId,
          academicYearName: yearInfo.name,
          academicYearStart: yearInfo.startDate,
          semester: r.semester as "1" | "2",
          score: r.score,
          fullScore: r.fullScore,
          subjectId: r.subjectId,
          title: r.title,
        }
      })
      .filter((r): r is NonNullable<typeof r> => r !== null)

    if (archiveRows.length === 0) {
      return null
    }

    // 调用 stats-service 纯函数构建成长点序列
    const points = buildGrowthArchivePoints(archiveRows)
    if (points.length === 0) {
      return null
    }

    // 计算总览统计
    const allNormalizedScores = rows
      .map((r) => normalize(toNumber(r.score), toNumber(r.fullScore)))
    const overallAverage = computeAverageScore(allNormalizedScores)
    const totalSubjects = new Set(rows.map((r) => r.subjectId)).size
    const totalAcademicYears = new Set(
      archiveRows.map((r) => r.academicYearId)
    ).size

    // 成长趋势：最新点平均分 - 第一个点平均分
    const firstPoint = points[0]
    const lastPoint = points[points.length - 1]
    const growthDelta = Math.round(
      (lastPoint.averageScore - firstPoint.averageScore) * 100
    ) / 100

    return {
      studentId,
      studentName: studentName ?? "Unknown",
      points,
      overallAverage,
      totalRecords: rows.length,
      totalSubjects,
      totalAcademicYears,
      growthDelta,
    }
  }
)

export interface SubjectComparisonParams {
  classId: string
  examId?: string
  semester?: "1" | "2"
  scope: DataScope
}

export const getSubjectComparison = cache(
  async (params: SubjectComparisonParams): Promise<SubjectComparisonItem[]> => {
    const scopeFilter = buildScopeClassFilter(params.scope)
    const conditions = [eq(gradeRecords.classId, params.classId)]
    if (params.examId) conditions.push(eq(gradeRecords.examId, params.examId))
    if (params.semester) conditions.push(eq(gradeRecords.semester, params.semester))
    if (scopeFilter) conditions.push(scopeFilter)

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

    if (rows.length === 0) return []

    // Fetch subject names via cross-module interface
    const subjectOptions = await getSubjectOptions()
    const subjectNameById = new Map<string, string>()
    for (const s of subjectOptions) subjectNameById.set(s.id, s.name)

    const bySubject = new Map<string, { name: string; scores: number[] }>()

    for (const r of rows) {
      const sid = r.subjectId
      if (!sid) continue
      const entry = bySubject.get(sid) ?? { name: subjectNameById.get(sid) ?? "Unknown", scores: [] }
      entry.scores.push(normalize(toNumber(r.score), toNumber(r.fullScore)))
      bySubject.set(sid, entry)
    }

    const result: SubjectComparisonItem[] = []
    for (const [subjectId, entry] of bySubject.entries()) {
      if (entry.scores.length === 0) continue
      const stats = computeSubjectComparisonStats(entry.scores)
      result.push({
        subjectId,
        subjectName: entry.name,
        ...stats,
      })
    }

    return result.sort((a, b) => b.averageScore - a.averageScore)
  }
)

export interface GradeDistributionParams {
  classId: string
  subjectId?: string
  examId?: string
  semester?: "1" | "2"
  scope: DataScope
  currentUserId?: string
}

export const getGradeDistribution = cache(
  async (params: GradeDistributionParams): Promise<GradeDistributionResult> => {
    const conditions = [eq(gradeRecords.classId, params.classId)]
    if (params.subjectId) conditions.push(eq(gradeRecords.subjectId, params.subjectId))
    if (params.examId) conditions.push(eq(gradeRecords.examId, params.examId))
    if (params.semester) conditions.push(eq(gradeRecords.semester, params.semester))

    if (params.scope.type === "class_members" && params.currentUserId) {
      conditions.push(eq(gradeRecords.studentId, params.currentUserId))
    }

    const scopeFilter = buildScopeClassFilter(params.scope)
    if (scopeFilter) conditions.push(scopeFilter)

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

    return computeGradeDistribution(rows)
  }
)

/**
 * v3-P2-7: 获取指定班级/科目下有成绩记录的考试列表，用于分析页考试筛选下拉框。
 * 仅返回 examId 非空且去重后的考试选项。
 */
export const getExamOptionsForGrades = cache(
  async (params: {
    classId: string
    subjectId?: string
    scope: DataScope
  }): Promise<Array<{ id: string; title: string }>> => {
    const conditions = [
      eq(gradeRecords.classId, params.classId),
      isNotNull(gradeRecords.examId),
      ne(gradeRecords.examId, ""),
    ]
    if (params.subjectId) conditions.push(eq(gradeRecords.subjectId, params.subjectId))

    const scopeFilter = buildScopeClassFilter(params.scope)
    if (scopeFilter) conditions.push(scopeFilter)

    const rows = await db
      .select({
        examId: gradeRecords.examId,
        title: gradeRecords.title,
      })
      .from(gradeRecords)
      .where(and(...conditions))

    // 去重：同一 examId 可能有多条成绩记录，保留第一条的 title
    const seen = new Set<string>()
    const result: Array<{ id: string; title: string }> = []
    for (const r of rows) {
      if (!r.examId || seen.has(r.examId)) continue
      seen.add(r.examId)
      result.push({ id: r.examId, title: r.title })
    }
    return result
  }
)

/**
 * v3-P2-9: 获取全校各年级成绩汇总（管理员视图）。
 * 按年级聚合平均分、及格率、优秀率、学生数、班级数。
 * 仅限管理员（scope.type === "all"）调用。
 */
export const getSchoolWideGradeSummary = cache(
  async (scope: DataScope): Promise<SchoolWideGradeSummary> => {
    // 管理员权限校验：仅 all scope 可调用
    if (scope.type !== "all") {
      return { grades: [], totals: { gradeCount: 0, classCount: 0, studentCount: 0, recordCount: 0, averageScore: 0, passRate: 0, excellentRate: 0 } }
    }

    const allGrades = await getGrades()
    if (allGrades.length === 0) {
      return { grades: [], totals: { gradeCount: 0, classCount: 0, studentCount: 0, recordCount: 0, averageScore: 0, passRate: 0, excellentRate: 0 } }
    }

    // 并行查询每个年级的班级列表
    const gradeClassMaps = await Promise.all(
      allGrades.map(async (g) => ({
        grade: g,
        classList: await getClassesByGradeId(g.id),
      })),
    )

    // 过滤掉无班级的年级
    const validGradeClassMaps = gradeClassMaps.filter((m) => m.classList.length > 0)
    if (validGradeClassMaps.length === 0) {
      return { grades: [], totals: { gradeCount: 0, classCount: 0, studentCount: 0, recordCount: 0, averageScore: 0, passRate: 0, excellentRate: 0 } }
    }

    // 并行查询每个年级的成绩记录（通过 classId inArray 过滤）
    const gradeStatsResults = await Promise.all(
      validGradeClassMaps.map(async (m) => {
        const classIds = m.classList.map((c) => c.id)
        const rows = await db
          .select({
            score: gradeRecords.score,
            fullScore: gradeRecords.fullScore,
            studentId: gradeRecords.studentId,
          })
          .from(gradeRecords)
          .where(inArray(gradeRecords.classId, classIds))

        const stats = computeGradeStats(rows)
        const uniqueStudents = new Set(rows.map((r) => r.studentId))

        return {
          grade: m.grade,
          classCount: m.classList.length,
          studentCount: uniqueStudents.size,
          recordCount: rows.length,
          stats,
        }
      }),
    )

    const gradeItems: SchoolWideGradeSummaryItem[] = gradeStatsResults
      .filter((r): r is typeof r & { stats: NonNullable<typeof r.stats> } => r.stats !== null)
      .map((r) => {
        const stats = r.stats
        return {
          gradeId: r.grade.id,
          gradeName: r.grade.name,
          schoolName: r.grade.school.name,
          classCount: r.classCount,
          studentCount: r.studentCount,
          recordCount: r.recordCount,
          averageScore: stats.average,
          passRate: stats.passRate,
          excellentRate: stats.excellentRate,
        }
      })
      .sort((a, b) => a.schoolName.localeCompare(b.schoolName) || a.gradeName.localeCompare(b.gradeName))

    // 计算全校汇总（按记录数加权平均）
    const totalClassCount = gradeItems.reduce((sum, g) => sum + g.classCount, 0)
    const totalStudentCount = gradeItems.reduce((sum, g) => sum + g.studentCount, 0)
    const totalRecordCount = gradeItems.reduce((sum, g) => sum + g.recordCount, 0)

    const weightedAvg = totalRecordCount > 0
      ? Math.round((gradeItems.reduce((sum, g) => sum + g.averageScore * g.recordCount, 0) / totalRecordCount) * 100) / 100
      : 0
    const weightedPassRate = totalRecordCount > 0
      ? Math.round((gradeItems.reduce((sum, g) => sum + g.passRate * g.recordCount, 0) / totalRecordCount) * 100) / 100
      : 0
    const weightedExcellentRate = totalRecordCount > 0
      ? Math.round((gradeItems.reduce((sum, g) => sum + g.excellentRate * g.recordCount, 0) / totalRecordCount) * 100) / 100
      : 0

    return {
      grades: gradeItems,
      totals: {
        gradeCount: gradeItems.length,
        classCount: totalClassCount,
        studentCount: totalStudentCount,
        recordCount: totalRecordCount,
        averageScore: weightedAvg,
        passRate: weightedPassRate,
        excellentRate: weightedExcellentRate,
      },
    }
  }
)

/**
 * 年级仪表盘 - 维度1：获取年级整体 + 按班级拆分的成绩分布。
 * 通过 getClassesByGradeId 获取年级下所有班级，再用 inArray 查询成绩记录，
 * 应用 buildScopeClassFilter 行级权限过滤，复用 computeGradeDistribution / computeGradeStats 纯函数。
 */
export interface GradeDistributionByGradeParams {
  gradeId: string
  subjectId?: string
  examId?: string
  semester?: "1" | "2"
  scope: DataScope
}

export const getGradeDistributionByGradeId = cache(
  async (params: GradeDistributionByGradeParams): Promise<GradeDistributionByGradeResult> => {
    const classRows = await getClassesByGradeId(params.gradeId)

    if (classRows.length === 0) {
      return {
        overall: computeGradeDistribution([]),
        stats: null,
        byClass: [],
      }
    }

    // scope 过滤：class_taught 仅保留当前教师所教班级
    const scope = params.scope
    const scopeClassIdSet =
      scope.type === "class_taught" ? new Set(scope.classIds) : null
    const allowedClassRows = scopeClassIdSet
      ? classRows.filter((c) => scopeClassIdSet.has(c.id))
      : classRows

    if (allowedClassRows.length === 0) {
      return {
        overall: computeGradeDistribution([]),
        stats: null,
        byClass: [],
      }
    }

    const allowedClassIds = allowedClassRows.map((c) => c.id)

    const conditions = [inArray(gradeRecords.classId, allowedClassIds)]
    if (params.subjectId) conditions.push(eq(gradeRecords.subjectId, params.subjectId))
    if (params.examId) conditions.push(eq(gradeRecords.examId, params.examId))
    if (params.semester) conditions.push(eq(gradeRecords.semester, params.semester))

    const scopeFilter = buildScopeClassFilter(params.scope)
    if (scopeFilter) conditions.push(scopeFilter)

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

    const overall = computeGradeDistribution(rows)
    const stats = computeGradeStats(rows)

    const byClassMap = new Map<string, typeof rows>()
    for (const r of rows) {
      const existing = byClassMap.get(r.classId)
      if (existing) {
        existing.push(r)
      } else {
        byClassMap.set(r.classId, [r])
      }
    }

    const byClass = allowedClassRows.map((cls) => {
      const classRowsForClass = byClassMap.get(cls.id) ?? []
      return {
        classId: cls.id,
        className: cls.name,
        distribution: computeGradeDistribution(classRowsForClass),
        stats: computeGradeStats(classRowsForClass),
      }
    })

    return { overall, stats, byClass }
  }
)
