import "server-only"

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

import { db } from "@/shared/db"
import { gradeRecords } from "@/shared/db/schema"
import { getStudentActiveClassId } from "@/modules/classes/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 { buildRankingTrendPoints, type RankingTrendEntry } from "./stats-service"
import type {
  ClassAverageTrendPoint,
  ClassAverageTrendResult,
  RankingTrendResult,
} from "./types"

/**
 * v3-P2-2: 班级平均成绩趋势点
 * 与 RankingTrendPoint 对齐（按 title 分组），用于在学生趋势图上叠加班级平均对比线。
 */
export type { ClassAverageTrendPoint, ClassAverageTrendResult }

/**
 * Get a student's ranking trend across assessments within their class.
 * Each point represents one assessment (grouped by title), with the
 * student's normalized score, rank, and total participants.
 *
 * P3 修复：添加 scope 参数，对 class_taught scope 校验学生归属
 */
export const getRankingTrend = cache(
  async (
    studentId: string,
    subjectId?: string,
    semester?: "1" | "2",
    scope?: DataScope
  ): Promise<RankingTrendResult | null> => {
    // P3 修复：对 class_taught scope 校验学生是否属于教师所教的班级
    if (scope?.type === "class_taught") {
      const allowedClassIds = new Set(scope.classIds)
      const studentClassId = await getStudentActiveClassId(studentId)
      if (studentClassId && !allowedClassIds.has(studentClassId)) {
        return null
      }
    }

    const studentNameMap = await getUserNamesByIds([studentId])
    const studentInfo = studentNameMap.get(studentId)
    if (!studentInfo) return null
    const studentName = studentInfo.name ?? "Unknown"

    const classId = await getStudentActiveClassId(studentId)

    if (!classId) {
      return {
        studentId,
        studentName,
        points: [],
      }
    }

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

    // 应用 scope 过滤
    if (scope) {
      const scopeFilter = buildScopeClassFilter(scope, studentId)
      if (scopeFilter) conditions.push(scopeFilter)
    }

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

    const byTitle = new Map<string, RankingTrendEntry>()

    for (const r of rows) {
      const entry = byTitle.get(r.title) ?? { date: r.createdAt, entries: [] }
      entry.entries.push({
        studentId: r.studentId,
        normalized: normalize(toNumber(r.score), toNumber(r.fullScore)),
      })
      byTitle.set(r.title, entry)
    }

    const points = buildRankingTrendPoints(byTitle, studentId)

    return {
      studentId,
      studentName,
      points,
    }
  }
)

/**
 * v3-P2-2: 获取班级平均成绩趋势（按 assessment title 分组）。
 *
 * 用于在学生个人成绩趋势图上叠加"班级平均"对比线，让学生/家长能直观
 * 看到个人与班级整体的差距。与 `getRankingTrend` 共享相同的过滤条件
 * 与分组逻辑，确保两条线的 X 轴对齐。
 *
 * @param studentId  目标学生 ID（用于定位其所在班级）
 * @param subjectId  可选科目过滤
 * @param semester   可选学期过滤
 * @param scope      数据权限范围
 */
export const getClassAverageTrend = cache(
  async (
    studentId: string,
    subjectId?: string,
    semester?: "1" | "2",
    scope?: DataScope
  ): Promise<ClassAverageTrendResult | null> => {
    // 对 class_taught scope 校验学生归属
    if (scope?.type === "class_taught") {
      const allowedClassIds = new Set(scope.classIds)
      const studentClassId = await getStudentActiveClassId(studentId)
      if (studentClassId && !allowedClassIds.has(studentClassId)) {
        return null
      }
    }

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

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

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

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

    // 按 title 分组，计算每次 assessment 的班级平均分（normalized 0-100）
    const byTitle = new Map<string, { date: Date; scores: number[] }>()
    for (const r of rows) {
      const normalized = normalize(toNumber(r.score), toNumber(r.fullScore))
      const entry = byTitle.get(r.title) ?? { date: r.createdAt, scores: [] }
      entry.scores.push(normalized)
      byTitle.set(r.title, entry)
    }

    const points: ClassAverageTrendPoint[] = []
    for (const [title, entry] of byTitle.entries()) {
      if (entry.scores.length === 0) continue
      const sum = entry.scores.reduce((acc, s) => acc + s, 0)
      const avg = Math.round((sum / entry.scores.length) * 100) / 100
      points.push({
        title,
        date: entry.date.toISOString(),
        averageScore: avg,
        studentCount: entry.scores.length,
      })
    }

    points.sort(
      (a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()
    )

    return {
      classId,
      points,
    }
  }
)
