import "server-only"

import { db } from "@/shared/db"
import { exams, examQuestions, examSubmissions, submissionAnswers } from "@/shared/db/schema"
import { count, eq, desc, and, inArray, asc, type SQL } from "drizzle-orm"
import { cache } from "react"
import { getClassGradeIdsByClassIds } from "@/modules/classes/data-access"
import { getSubjectOptions } from "@/modules/school/data-access"
import { getQuestionTypeMapByIds } from "@/modules/questions/data-access"

import type { GradeExamsResult, GradeExamItem, ExamForGradeEntry, ExamOptionForEntry } from "./types"
import type { DataScope } from "@/shared/types/permissions"

import { parseExamMeta, getString, getNumber, toExamStatus } from "./data-access"

// ---------------------------------------------------------------------------
// 跨模块查询接口（供其他模块调用，避免直查 exams/examSubmissions 表）
// 本文件从 data-access.ts 拆分而来，原文件超过 1000 行硬上限。
// ---------------------------------------------------------------------------

export type ExamsDashboardStats = {
  examCount: number
}

export const getExamsDashboardStats = cache(async (scope?: DataScope): Promise<ExamsDashboardStats> => {
  const conditions = []

  if (scope && scope.type !== "all") {
    if (scope.type === "owned") {
      conditions.push(eq(exams.creatorId, scope.userId))
    }
    if (scope.type === "grade_managed") {
      // P0 fix: empty gradeIds must NOT bypass filtering
      if (scope.gradeIds.length === 0) {
        conditions.push(eq(exams.id, "__none__"))
      } else {
        conditions.push(inArray(exams.gradeId, scope.gradeIds))
      }
    }
    if (scope.type === "class_taught") {
      // P0 fix: empty classIds must NOT bypass filtering
      if (scope.classIds.length === 0) {
        conditions.push(eq(exams.id, "__none__"))
      } else {
        const classGradeMap = await getClassGradeIdsByClassIds(scope.classIds)
        const gradeIds = Array.from(new Set(classGradeMap.values()))
        if (gradeIds.length > 0) {
          conditions.push(inArray(exams.gradeId, gradeIds))
        } else {
          conditions.push(eq(exams.id, "__none__"))
        }
      }
    }
  }

  const [row] = await db
    .select({ value: count() })
    .from(exams)
    .where(conditions.length ? and(...conditions) : undefined)

  return { examCount: Number(row?.value ?? 0) }
})

/**
 * 获取指定年级 ID 列表对应的所有考试 ID。
 * 供 homework/grades 等模块跨模块调用使用。
 */
export const getExamIdsByGradeIds = async (gradeIds: string[]): Promise<string[]> => {
  if (gradeIds.length === 0) return []
  const rows = await db
    .select({ id: exams.id })
    .from(exams)
    .where(inArray(exams.gradeId, gradeIds))
  return rows.map((r) => r.id)
}

/**
 * 获取考试的基本信息（含题目列表），供 homework 模块创建作业时使用。
 * 返回的数据包含 examId、title、subjectId、structure 和题目列表。
 */
export type ExamWithQuestionsForHomework = {
  id: string
  title: string
  subjectId: string | null
  structure: unknown
  questions: Array<{ questionId: string; score: number | null; order: number | null }>
}

export const getExamWithQuestionsForHomework = async (
  examId: string
): Promise<ExamWithQuestionsForHomework | null> => {
  const exam = await db.query.exams.findFirst({
    where: eq(exams.id, examId),
    with: {
      questions: {
        orderBy: (examQuestions, { asc }) => [asc(examQuestions.order)],
      },
    },
  })
  if (!exam) return null
  return {
    id: exam.id,
    title: exam.title,
    subjectId: exam.subjectId,
    structure: exam.structure,
    questions: exam.questions.map((q) => ({
      questionId: q.questionId,
      score: q.score ?? null,
      order: q.order ?? null,
    })),
  }
}

/**
 * 获取多个考试的 subjectId 映射（examId -> subjectId）。
 * 供 homework 模块查询作业对应科目时使用。
 */
export const getExamSubjectIdMap = async (examIds: string[]): Promise<Map<string, string | null>> => {
  if (examIds.length === 0) return new Map()
  const rows = await db
    .select({ id: exams.id, subjectId: exams.subjectId })
    .from(exams)
    .where(inArray(exams.id, examIds))
  const map = new Map<string, string | null>()
  for (const r of rows) map.set(r.id, r.subjectId)
  return map
}

/**
 * 获取考试标题。
 * 供 proctoring 等模块跨模块调用使用。
 */
export const getExamTitleById = async (examId: string): Promise<string | null> => {
  const [row] = await db
    .select({ title: exams.title })
    .from(exams)
    .where(eq(exams.id, examId))
    .limit(1)
  return row?.title ?? null
}

/**
 * 获取考试的基本信息（含监考模式相关字段），供 proctoring 模块使用。
 */
export type ExamForProctoring = {
  id: string
  title: string
  examMode: string | null
  durationMinutes: number | null
  shuffleQuestions: boolean | null
  allowLateStart: boolean | null
  lateStartGraceMinutes: number | null
  antiCheatEnabled: boolean | null
}

export const getExamForProctoringCrossModule = async (examId: string): Promise<ExamForProctoring | null> => {
  const exam = await db.query.exams.findFirst({
    where: eq(exams.id, examId),
  })
  if (!exam) return null
  return {
    id: exam.id,
    title: exam.title,
    examMode: exam.examMode,
    durationMinutes: exam.durationMinutes ?? null,
    shuffleQuestions: exam.shuffleQuestions ?? false,
    allowLateStart: exam.allowLateStart ?? false,
    lateStartGraceMinutes: exam.lateStartGraceMinutes ?? 0,
    antiCheatEnabled: exam.antiCheatEnabled ?? false,
  }
}

/**
 * 校验提交记录归属（监考事件上报前的安全校验）。
 * 供 proctoring 模块跨模块调用使用。
 */
export const getExamSubmissionForProctoringCrossModule = async (
  submissionId: string,
  studentId: string
): Promise<{ id: string; examId: string; studentId: string } | null> => {
  const submission = await db.query.examSubmissions.findFirst({
    where: and(
      eq(examSubmissions.id, submissionId),
      eq(examSubmissions.studentId, studentId),
    ),
    columns: {
      id: true,
      examId: true,
      studentId: true,
    },
  })
  return submission ?? null
}

/**
 * 获取考试提交记录及其答题数据，供 diagnostic 模块更新知识点掌握度使用。
 */
export type ExamSubmissionWithAnswers = {
  studentId: string
  answers: Array<{ questionId: string; score: number | null }>
}

export const getExamSubmissionWithAnswers = async (
  submissionId: string
): Promise<ExamSubmissionWithAnswers | null> => {
  const [submission] = await db
    .select({ studentId: examSubmissions.studentId })
    .from(examSubmissions)
    .where(eq(examSubmissions.id, submissionId))
    .limit(1)
  if (!submission) return null

  const answers = await db
    .select({
      questionId: submissionAnswers.questionId,
      score: submissionAnswers.score,
    })
    .from(submissionAnswers)
    .where(eq(submissionAnswers.submissionId, submissionId))

  return {
    studentId: submission.studentId,
    answers,
  }
}

/**
 * 获取一场考试的所有提交记录（含学生 ID 和状态），供 proctoring 模块使用。
 */
export type ExamSubmissionForProctoringSummary = {
  id: string
  studentId: string
  status: string | null
}

export const getExamSubmissionsForExam = async (
  examId: string
): Promise<ExamSubmissionForProctoringSummary[]> => {
  const rows = await db
    .select({
      id: examSubmissions.id,
      studentId: examSubmissions.studentId,
      status: examSubmissions.status,
    })
    .from(examSubmissions)
    .where(eq(examSubmissions.examId, examId))
  return rows
}

/**
 * 批量插入考试题目（跨模块写接口）。
 * 供 lesson-preparation 模块发布课案为作业时使用，避免直接操作 examQuestions 表。
 */
export const addExamQuestions = async (
  examId: string,
  items: Array<{ questionId: string; score: number; order: number }>
): Promise<void> => {
  if (items.length === 0) return
  await db.insert(examQuestions).values(
    items.map((it) => ({
      examId,
      questionId: it.questionId,
      score: it.score,
      order: it.order,
    }))
  )
}

/**
 * 年级仪表盘 - 维度3：获取年级下所有考试 + 提交统计。
 * exams 表有直接 gradeId 字段，配合 examSubmissions 聚合提交数/已评分数/平均分。
 */
export const getExamsByGradeId = cache(
  async (params: { gradeId: string; scope: DataScope }): Promise<GradeExamsResult> => {
    const conditions: SQL[] = [eq(exams.gradeId, params.gradeId)]

    // scope 过滤
    if (params.scope.type === "owned") {
      conditions.push(eq(exams.creatorId, params.scope.userId))
    }
    if (params.scope.type === "grade_managed") {
      if (params.scope.gradeIds.length === 0) {
        conditions.push(eq(exams.id, "__none__"))
      } else {
        // grade_managed 且当前 gradeId 在管辖范围内才可见
        if (!params.scope.gradeIds.includes(params.gradeId)) {
          return {
            gradeId: params.gradeId,
            exams: [],
            totals: { examCount: 0, publishedCount: 0, draftCount: 0, archivedCount: 0, totalSubmissions: 0, totalGraded: 0 },
          }
        }
      }
    }
    if (params.scope.type === "class_taught") {
      // 教师仅能看到所教班级对应年级的考试
      if (params.scope.classIds.length === 0) {
        conditions.push(eq(exams.id, "__none__"))
      } else {
        const classGradeMap = await getClassGradeIdsByClassIds(params.scope.classIds)
        const gradeIds = Array.from(new Set(classGradeMap.values()))
        if (!gradeIds.includes(params.gradeId)) {
          return {
            gradeId: params.gradeId,
            exams: [],
            totals: { examCount: 0, publishedCount: 0, draftCount: 0, archivedCount: 0, totalSubmissions: 0, totalGraded: 0 },
          }
        }
      }
    }

    const examRows = await db
      .select({
        id: exams.id,
        title: exams.title,
        status: exams.status,
        subjectId: exams.subjectId,
        startTime: exams.startTime,
        createdAt: exams.createdAt,
      })
      .from(exams)
      .where(and(...conditions))
      .orderBy(desc(exams.createdAt))

    if (examRows.length === 0) {
      return {
        gradeId: params.gradeId,
        exams: [],
        totals: { examCount: 0, publishedCount: 0, draftCount: 0, archivedCount: 0, totalSubmissions: 0, totalGraded: 0 },
      }
    }

    const examIds = examRows.map((e) => e.id)

    // 并行查询：科目名称 + 提交统计
    const [subjectOptions, submissionRows] = await Promise.all([
      getSubjectOptions(),
      db
        .select({
          examId: examSubmissions.examId,
          status: examSubmissions.status,
          score: examSubmissions.score,
        })
        .from(examSubmissions)
        .where(inArray(examSubmissions.examId, examIds)),
    ])

    const subjectNameById = new Map<string, string>()
    for (const s of subjectOptions) subjectNameById.set(s.id, s.name)

    // 按考试分组统计提交
    const statsByExam = new Map<string, { total: number; graded: number; scoreSum: number }>()
    for (const s of submissionRows) {
      const entry = statsByExam.get(s.examId) ?? { total: 0, graded: 0, scoreSum: 0 }
      entry.total += 1
      if (s.status === "graded" && s.score !== null) {
        entry.graded += 1
        entry.scoreSum += Number(s.score)
      }
      statsByExam.set(s.examId, entry)
    }

    const items: GradeExamItem[] = examRows.map((e) => {
      const stats = statsByExam.get(e.id) ?? { total: 0, graded: 0, scoreSum: 0 }
      return {
        id: e.id,
        title: e.title,
        status: toExamStatus(e.status),
        subjectId: e.subjectId,
        subjectName: e.subjectId ? (subjectNameById.get(e.subjectId) ?? null) : null,
        scheduledAt: e.startTime ? e.startTime.toISOString() : null,
        createdAt: e.createdAt.toISOString(),
        submissionCount: stats.total,
        gradedCount: stats.graded,
        averageScore: stats.graded > 0 ? Math.round((stats.scoreSum / stats.graded) * 100) / 100 : null,
      }
    })

    const totals = {
      examCount: items.length,
      publishedCount: items.filter((i) => i.status === "published").length,
      draftCount: items.filter((i) => i.status === "draft").length,
      archivedCount: items.filter((i) => i.status === "archived").length,
      totalSubmissions: items.reduce((sum, i) => sum + i.submissionCount, 0),
      totalGraded: items.reduce((sum, i) => sum + i.gradedCount, 0),
    }

    return { gradeId: params.gradeId, exams: items, totals }
  }
)

/**
 * 获取可用于成绩录入的试卷列表（按 scope 过滤，只返回有题目的试卷）。
 */
export const getExamsForGradeEntry = cache(
  async (scope: DataScope): Promise<ExamOptionForEntry[]> => {
    const conditions: SQL[] = []

    if (scope.type === "owned") {
      conditions.push(eq(exams.creatorId, scope.userId))
    }
    if (scope.type === "class_taught" && scope.classIds.length > 0) {
      const classGradeMap = await getClassGradeIdsByClassIds(scope.classIds)
      const gradeIds = Array.from(new Set(classGradeMap.values()))
      if (gradeIds.length > 0) {
        conditions.push(inArray(exams.gradeId, gradeIds))
      } else {
        conditions.push(eq(exams.id, "__none__"))
      }
    } else if (scope.type === "class_taught") {
      conditions.push(eq(exams.id, "__none__"))
    }
    if (scope.type === "grade_managed" && scope.gradeIds.length > 0) {
      conditions.push(inArray(exams.gradeId, scope.gradeIds))
    } else if (scope.type === "grade_managed") {
      conditions.push(eq(exams.id, "__none__"))
    }

    const examRows = await db.query.exams.findMany({
      where: conditions.length ? and(...conditions) : undefined,
      orderBy: [desc(exams.createdAt)],
      with: { subject: true, gradeEntity: true },
    })

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

    const examIds = examRows.map((e) => e.id)
    const questionCountRows = await db
      .select({ examId: examQuestions.examId, count: count() })
      .from(examQuestions)
      .where(inArray(examQuestions.examId, examIds))
      .groupBy(examQuestions.examId)

    const questionCountMap = new Map(
      questionCountRows.map((r) => [r.examId, Number(r.count)])
    )

    return examRows
      .filter((e) => (questionCountMap.get(e.id) ?? 0) > 0)
      .map((e) => {
        const meta = parseExamMeta(e.description ?? null)
        return {
          id: e.id,
          title: e.title,
          subjectName: e.subject?.name ?? getString(meta, "subject") ?? "General",
          gradeName: e.gradeEntity?.name ?? getString(meta, "grade") ?? "General",
          questionCount: questionCountMap.get(e.id) ?? 0,
          totalScore: getNumber(meta, "totalScore") ?? 100,
        }
      })
  }
)

/**
 * 获取单个试卷详情（含题目列表），用于成绩录入表格表头。
 */
export const getExamForGradeEntry = cache(
  async (examId: string, scope?: DataScope): Promise<ExamForGradeEntry | null> => {
    const exam = await db.query.exams.findFirst({
      where: eq(exams.id, examId),
      with: { subject: true, gradeEntity: true },
    })

    if (!exam) return null

    if (scope && scope.type !== "all") {
      if (scope.type === "owned" && exam.creatorId !== scope.userId) return null
      if (scope.type === "grade_managed") {
        if (scope.gradeIds.length === 0) return null
        if (!scope.gradeIds.includes(exam.gradeId ?? "")) return null
      }
      if (scope.type === "class_taught") {
        if (scope.classIds.length === 0) return null
        const classGradeMap = await getClassGradeIdsByClassIds(scope.classIds)
        const gradeIds = Array.from(new Set(classGradeMap.values()))
        if (gradeIds.length === 0) return null
        if (!gradeIds.includes(exam.gradeId ?? "")) return null
      }
    }

    const questionRows = await db
      .select({
        questionId: examQuestions.questionId,
        score: examQuestions.score,
        order: examQuestions.order,
      })
      .from(examQuestions)
      .where(eq(examQuestions.examId, examId))
      .orderBy(asc(examQuestions.order))

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

    // P0-1 修复：不再直接 JOIN questions 表，改为调用 questions 模块 data-access 获取题目类型
    const questionIds = questionRows.map((q) => q.questionId)
    const questionTypeMap = await getQuestionTypeMapByIds(questionIds)

    const meta = parseExamMeta(exam.description ?? null)
    const computedTotal = questionRows.reduce((sum, q) => sum + (q.score ?? 0), 0)

    return {
      id: exam.id,
      title: exam.title,
      subjectId: exam.subjectId,
      gradeId: exam.gradeId,
      totalScore: getNumber(meta, "totalScore") ?? computedTotal,
      questions: questionRows.map((q) => ({
        id: q.questionId,
        order: q.order ?? 0,
        score: q.score ?? 0,
        type: questionTypeMap.get(q.questionId) ?? "text",
      })),
    }
  }
)
