import "server-only"

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

import { db } from "@/shared/db"
import { errorBookItems } from "@/shared/db/schema"
import { getExamSubmissionDataForErrorCollection } from "@/modules/exams/data-access-error-collection"
import { getHomeworkSubmissionDataForErrorCollection } from "@/modules/homework/data-access-error-collection"
import {
  getKnowledgePointsForQuestions,
  getQuestionsContentForErrorCollection,
} from "@/modules/questions/data-access"
import { extractCorrectAnswer } from "@/shared/lib/question-content"

/**
 * 错题采集的答案数据（由各模块的跨模块接口返回）
 */
type AnswerForCollection = {
  questionId: string
  answerContent: unknown
  score: number | null
  feedback: string | null
  maxScore: number
}

/**
 * 从答案列表中采集错题并写入 errorBookItems 表。
 *
 * 这是 collectFromExamSubmission 和 collectFromHomeworkSubmission 的共享逻辑：
 * 1. 筛选错题（score < maxScore）
 * 2. 查询已存在的错题避免重复
 * 3. 获取题目关联的知识点（通过 questions 模块跨模块接口）
 * 4. 获取题目内容并提取正确答案（通过 questions 模块 + shared 纯函数）
 * 5. 批量插入错题
 *
 * @param studentId 学生 ID
 * @param sourceType 错题来源类型 ("exam" | "homework")
 * @param sourceId 来源提交 ID
 * @param subjectId 学科 ID（可为 null）
 * @param answers 答案列表
 * @returns 新采集的错题数量
 */
async function collectErrorItemsFromAnswers(
  studentId: string,
  sourceType: "exam" | "homework",
  sourceId: string,
  subjectId: string | null,
  answers: AnswerForCollection[],
): Promise<number> {
  // 筛选错题：得分为 0 或低于满分
  const wrongAnswers = answers.filter((a) => (a.score ?? 0) < a.maxScore)

  if (wrongAnswers.length === 0) return 0

  const wrongQuestionIds = wrongAnswers.map((a) => a.questionId)

  // 并行查询：已存在的错题、知识点关联、题目内容
  const [existing, kpMap, questionContentMap] = await Promise.all([
    db
      .select({ questionId: errorBookItems.questionId })
      .from(errorBookItems)
      .where(
        and(
          eq(errorBookItems.studentId, studentId),
          inArray(errorBookItems.questionId, wrongQuestionIds),
        ),
      ),
    getKnowledgePointsForQuestions(wrongQuestionIds),
    getQuestionsContentForErrorCollection(wrongQuestionIds),
  ])

  const existingSet = new Set(existing.map((e) => e.questionId))

  const now = new Date()
  const toInsert = wrongAnswers
    .filter((a) => !existingSet.has(a.questionId))
    .map((a) => {
      // 从题目内容中提取正确答案
      const questionData = questionContentMap.get(a.questionId)
      const correctAnswer = questionData
        ? extractCorrectAnswer(questionData.type, questionData.content)
        : null

      // 提取知识点 ID 列表
      const kpLinks = kpMap.get(a.questionId) ?? []
      const knowledgePointIds = kpLinks.length > 0 ? kpLinks.map((k) => k.knowledgePointId) : null

      return {
        id: createId(),
        studentId,
        questionId: a.questionId,
        sourceType,
        sourceId,
        studentAnswer: a.answerContent,
        correctAnswer,
        subjectId,
        knowledgePointIds,
        status: "new" as const,
        masteryLevel: 0,
        nextReviewAt: now,
        reviewInterval: 1,
        reviewCount: 0,
        correctStreak: 0,
        note: a.feedback ?? null,
        errorTags: null,
      }
    })

  if (toInsert.length > 0) {
    await db.insert(errorBookItems).values(toInsert)
  }

  return toInsert.length
}

/**
 * 自动采集：从考试提交中收集错题。
 *
 * 通过 exams 模块的跨模块接口获取提交数据，避免直接查询
 * examSubmissions、submissionAnswers、examQuestions、exams 等表。
 *
 * @param submissionId 考试提交 ID
 * @param studentId 学生 ID（用于校验提交归属）
 * @returns 新采集的错题数量
 * @throws 若提交记录不存在或 studentId 不匹配
 */
export async function collectFromExamSubmission(
  submissionId: string,
  studentId: string,
): Promise<number> {
  const data = await getExamSubmissionDataForErrorCollection(submissionId, studentId)
  if (!data) throw new Error("考试提交记录不存在")

  return collectErrorItemsFromAnswers(
    studentId,
    "exam",
    submissionId,
    data.subjectId,
    data.answers,
  )
}

/**
 * 自动采集：从作业提交中收集错题。
 *
 * 通过 homework 模块的跨模块接口获取提交数据，避免直接查询
 * homeworkSubmissions、homeworkAssignments、homeworkAnswers、
 * homeworkAssignmentQuestions、exams 等表。
 *
 * @param submissionId 作业提交 ID
 * @param studentId 学生 ID
 * @returns 新采集的错题数量
 * @throws 若提交记录不存在
 */
export async function collectFromHomeworkSubmission(
  submissionId: string,
  studentId: string,
): Promise<number> {
  const data = await getHomeworkSubmissionDataForErrorCollection(submissionId)
  if (!data) throw new Error("作业提交记录不存在")

  return collectErrorItemsFromAnswers(
    studentId,
    "homework",
    submissionId,
    data.subjectId,
    data.answers,
  )
}
