import "server-only"

import { createId } from "@paralleldrive/cuid2"
import { and, eq, inArray } from "drizzle-orm"

import { db } from "@/shared/db"
import {
  examQuestions,
  examSubmissions,
  gradeRecordAnswers,
  gradeRecords,
  submissionAnswers,
} from "@/shared/db/schema"

import type { BatchGradeEntryByExamInput } from "./schema"

/**
 * 按试卷批量录入成绩的数据访问层。
 *
 * P1-2 重构：从 data-access.ts 拆分而来。
 * 该文件专注于“按试卷录入”这一独立用例的数据写入逻辑。
 */

/**
 * 按试卷批量录入成绩（每题得分）。
 *
 * 写入流程（单事务）：
 * 1. 查询 exam_questions 获取每题满分，并校验所有 questionId 属于该试卷
 * 2. 查询已有 exam_submissions（避免主键冲突）
 * 3. 为每个学生：
 *    - 创建 grade_records（score = 各题得分之和）
 *    - 创建 grade_record_answers（每题得分）
 *    - 创建/更新 exam_submissions（status='graded'，投影供下游模块使用）
 *    - 创建/替换 submission_answers（answerContent=null，投影每题得分）
 *
 * 投影设计：教师录入的成绩通过 exam_submissions + submission_answers 体现，
 * 这样错题集、成绩分析等下游模块无需改造即可读取。
 *
 * 返回每条记录的 { gradeRecordId, studentId, submissionId }，
 * 供调用方在事务后触发错题采集等后置钩子。
 */
export interface BatchGradeRecordResult {
  gradeRecordId: string
  studentId: string
  submissionId: string
}

export async function batchCreateGradeRecordsByExam(
  data: BatchGradeEntryByExamInput,
  recordedBy: string
): Promise<BatchGradeRecordResult[]> {
  if (data.records.length === 0) return []

  const now = new Date()
  const results: BatchGradeRecordResult[] = []

  await db.transaction(async (tx) => {
    // 1. 查询试卷题目（获取每题满分 + 验证 questionId 归属）
    const examQuestionRows = await tx
      .select({
        questionId: examQuestions.questionId,
        score: examQuestions.score,
      })
      .from(examQuestions)
      .where(eq(examQuestions.examId, data.examId))

    if (examQuestionRows.length === 0) {
      throw new Error("Exam has no questions, cannot enter grades")
    }

    const questionFullScoreMap = new Map(
      examQuestionRows.map((q) => [q.questionId, q.score ?? 0])
    )

    // 校验所有 questionId 都属于该试卷
    for (const record of data.records) {
      for (const answer of record.answers) {
        if (!questionFullScoreMap.has(answer.questionId)) {
          throw new Error(
            `Question ${answer.questionId} does not belong to exam ${data.examId}`
          )
        }
      }
    }

    // 2. 查询已有 exam_submissions（避免冲突）
    const studentIds = data.records.map((r) => r.studentId)
    const existingSubmissions = await tx
      .select({
        id: examSubmissions.id,
        studentId: examSubmissions.studentId,
      })
      .from(examSubmissions)
      .where(
        and(
          eq(examSubmissions.examId, data.examId),
          inArray(examSubmissions.studentId, studentIds)
        )
      )
    const existingSubmissionMap = new Map(
      existingSubmissions.map((s) => [s.studentId, s.id])
    )

    // 3. 为每个学生创建记录
    for (const record of data.records) {
      const gradeRecordId = createId()

      const totalScore = record.answers.reduce(
        (sum, a) => sum + a.score,
        0
      )

      // 3a. grade_records
      await tx.insert(gradeRecords).values({
        id: gradeRecordId,
        studentId: record.studentId,
        classId: data.classId,
        subjectId: data.subjectId,
        examId: data.examId,
        academicYearId: null,
        title: data.title,
        score: String(totalScore),
        fullScore: String(data.fullScore),
        type: data.type ?? "exam",
        semester: data.semester ?? "1",
        recordedBy,
        remark: record.remark ?? null,
      })

      // 3b. grade_record_answers
      const answerRows = record.answers.map((a) => ({
        id: createId(),
        gradeRecordId,
        questionId: a.questionId,
        score: String(a.score),
        fullScore: String(questionFullScoreMap.get(a.questionId) ?? 0),
        feedback: null,
      }))
      await tx.insert(gradeRecordAnswers).values(answerRows)

      // 3c. 投影到 exam_submissions
      const existingSubmissionId = existingSubmissionMap.get(record.studentId)
      let submissionId: string

      if (existingSubmissionId) {
        await tx
          .update(examSubmissions)
          .set({
            score: totalScore,
            status: "graded",
            submittedAt: now,
            updatedAt: now,
          })
          .where(eq(examSubmissions.id, existingSubmissionId))
        submissionId = existingSubmissionId

        // 删除旧 submission_answers
        await tx
          .delete(submissionAnswers)
          .where(eq(submissionAnswers.submissionId, submissionId))
      } else {
        submissionId = createId()
        await tx.insert(examSubmissions).values({
          id: submissionId,
          examId: data.examId,
          studentId: record.studentId,
          score: totalScore,
          status: "graded",
          submittedAt: now,
        })
      }

      // 3d. submission_answers 投影（answerContent=null，只有得分）
      const submissionAnswerRows = record.answers.map((a) => ({
        id: createId(),
        submissionId,
        questionId: a.questionId,
        answerContent: null,
        score: a.score,
        feedback: null,
      }))
      await tx.insert(submissionAnswers).values(submissionAnswerRows)

      results.push({ gradeRecordId, studentId: record.studentId, submissionId })
    }
  })

  return results
}
