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 { normalize, toNumber } from "./lib/grade-utils"
import { buildRankingTrendPoints, type RankingTrendEntry } from "./stats-service"
import type {
  RankingTrendResult,
} from "./types"

/**
 * 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.
 */
export const getRankingTrend = cache(
  async (
    studentId: string,
    subjectId?: string,
    semester?: "1" | "2"
  ): Promise<RankingTrendResult | 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))

    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,
    }
  }
)
