"use server"

import { revalidatePath } from "next/cache"
import { getTranslations } from "next-intl/server"
import { requirePermission } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import type { ActionState } from "@/shared/types/action-state"
import { handleActionError, safeJsonParse } from "@/shared/lib/action-utils"

import {
  CreateGradeRecordSchema,
  BatchCreateGradeRecordSchema,
  BatchGradeEntryByExamSchema,
  UpdateGradeRecordSchema,
  DeleteGradeRecordSchema,
  GetGradeRecordByIdSchema,
  GradeQuerySchema,
  ClassGradeStatsQuerySchema,
  StudentGradeSummaryQuerySchema,
  ClassRankingQuerySchema,
  ExportGradesSchema,
} from "./schema"
import {
  createGradeRecord,
  batchCreateGradeRecords,
  undoBatchCreateGradeRecords,
  updateGradeRecord,
  deleteGradeRecord,
  bulkDeleteGradeRecords,
  getGradeRecords,
  getGradeRecordById,
  getClassGradeStatsWithMeta,
  getStudentGradeSummary,
  getClassRanking,
} from "./data-access"
import { batchCreateGradeRecordsByExam } from "./data-access-exam-entry"
import type { PaginatedGradeRecords } from "./data-access"
import { updateMasteryFromExamScore } from "@/modules/diagnostic/data-access"
import { getExamForGradeEntry } from "@/modules/exams/data-access"
import { collectFromExamSubmission } from "@/modules/error-book/data-access"
import {
  exportGradeRecordsToExcel,
  exportClassGradeReportToExcel,
  exportStudentGradeRecordsToExcel,
} from "./export"
import { formatDateForFile } from "@/shared/lib/utils"
import { notifyGradeEntered, notifyScoreAnomalyIfNeeded } from "./lib/notify"
import { assertClassInScope } from "./lib/scope-check"
import type { GradeQueryParams, GradeStats } from "./types"
import type {
  StudentGradeSummary,
  ClassRankingItem,
  GradeRecord,
} from "./types"

/**
 * grades 模块核心 Server Actions（编排层）。
 *
 * P1-1 重构：
 * - 草稿相关 3 个 Action 已迁移至 actions-draft.ts
 * - 通知逻辑 notifyGradeEntered 已迁移至 lib/notify.ts
 * - 所有错误消息已接入 i18n（P1-3）
 * - assertClassInScope 返回错误码，由调用方通过 i18n 翻译（P1-4）
 */

export async function createGradeRecordAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    const parsed = CreateGradeRecordSchema.safeParse({
      studentId: formData.get("studentId"),
      classId: formData.get("classId"),
      subjectId: formData.get("subjectId"),
      examId: formData.get("examId") || undefined,
      academicYearId: formData.get("academicYearId") || undefined,
      title: formData.get("title"),
      score: formData.get("score"),
      fullScore: formData.get("fullScore") || undefined,
      type: formData.get("type") || undefined,
      semester: formData.get("semester") || undefined,
      remark: formData.get("remark") || undefined,
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidFormData"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const id = await createGradeRecord(parsed.data, ctx.userId)
    // v3-P1-5：成绩录入后更新诊断掌握度
    if (parsed.data.examId) {
      try {
        await updateMasteryFromExamScore(
          parsed.data.studentId,
          parsed.data.examId,
          parsed.data.score,
          parsed.data.fullScore ?? 100,
        )
      } catch {
        // 掌握度更新失败不应阻断成绩录入
      }
    }
    // v4-P1-6：成绩录入后通知学生和家长
    try {
      await notifyGradeEntered({
        studentIds: [parsed.data.studentId],
        title: parsed.data.title,
        subjectId: parsed.data.subjectId,
        score: parsed.data.score,
        fullScore: parsed.data.fullScore ?? 100,
      })
    } catch {
      // 通知失败不阻断成绩录入
    }
    revalidatePath("/teacher/grades")
    return { success: true, message: t("action.recordCreated"), data: id }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function batchCreateGradeRecordsAction(
  prevState: ActionState<string[]> | null,
  formData: FormData
): Promise<ActionState<string[]>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    const recordsJson = formData.get("recordsJson")
    if (typeof recordsJson !== "string" || recordsJson.length === 0) {
      return { success: false, message: t("action.missingRecordsData") }
    }

    // P3 修复：使用 safeJsonParse 替代 JSON.parse，避免 SyntaxError 暴露
    const records = safeJsonParse<unknown>(recordsJson, t("action.invalidJson"))

    const parsed = BatchCreateGradeRecordSchema.safeParse({
      classId: formData.get("classId"),
      subjectId: formData.get("subjectId"),
      examId: formData.get("examId") || undefined,
      academicYearId: formData.get("academicYearId") || undefined,
      title: formData.get("title"),
      fullScore: formData.get("fullScore") || undefined,
      type: formData.get("type") || undefined,
      semester: formData.get("semester") || undefined,
      records,
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidFormData"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    // v3-P2-3：返回创建的记录 ID 列表，供前端撤销使用
    const ids = await batchCreateGradeRecords(parsed.data, ctx.userId)
    // v3-P1-5：批量成绩录入后更新诊断掌握度
    if (parsed.data.examId) {
      const fullScore = parsed.data.fullScore ?? 100
      for (const record of parsed.data.records) {
        try {
          await updateMasteryFromExamScore(
            record.studentId,
            parsed.data.examId,
            record.score,
            fullScore,
          )
        } catch {
          // 掌握度更新失败不应阻断成绩录入
        }
      }
    }
    // v4-P1-6：批量成绩录入后通知学生和家长
    try {
      await notifyGradeEntered({
        studentIds: parsed.data.records.map((r) => r.studentId),
        title: parsed.data.title,
        subjectId: parsed.data.subjectId,
        fullScore: parsed.data.fullScore ?? 100,
      })
    } catch {
      // 通知失败不阻断成绩录入
    }

    // P3-2：批量录入后检测成绩异常（下降超过 10 分 / 10%），异常时通知学生 + 家长
    try {
      await notifyScoreAnomalyIfNeeded({
        studentIds: parsed.data.records.map((r) => r.studentId),
        classId: parsed.data.classId,
        subjectId: parsed.data.subjectId,
        scope: ctx.dataScope,
      })
    } catch {
      // 异常检测失败不阻断成绩录入
    }

    revalidatePath("/teacher/grades")
    return {
      success: true,
      message: t("action.recordsCreated", { count: ids.length }),
      data: ids,
    }
  } catch (e) {
    return handleActionError(e)
  }
}

/**
 * 按试卷批量录入成绩（每题得分）。
 *
 * 必须指定试卷 ID，系统自动从试卷带出科目、标题、满分和题目列表。
 * 教师只需为每个学生填写每题得分，总分自动计算。
 *
 * 写入时同步投影到 exam_submissions + submission_answers，
 * 使错题集、成绩分析等下游模块无需改造即可读取。
 */
export async function batchCreateGradeRecordsByExamAction(
  prevState: ActionState<string[]> | null,
  formData: FormData
): Promise<ActionState<string[]>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    const examId = formData.get("examId")
    const classId = formData.get("classId")
    const recordsJson = formData.get("recordsJson")

    if (typeof examId !== "string" || examId.length === 0) {
      return { success: false, message: t("action.missingExamId") }
    }
    if (typeof classId !== "string" || classId.length === 0) {
      return { success: false, message: t("action.missingClassId") }
    }
    if (typeof recordsJson !== "string" || recordsJson.length === 0) {
      return { success: false, message: t("action.missingRecords") }
    }

    // 获取试卷详情（验证试卷存在 + scope 校验 + 获取 subjectId/fullScore/title）
    const exam = await getExamForGradeEntry(examId, ctx.dataScope)
    if (!exam) {
      return { success: false, message: t("action.examNotFound") }
    }
    if (exam.questions.length === 0) {
      return { success: false, message: t("action.examNoQuestions") }
    }
    if (!exam.subjectId) {
      return { success: false, message: t("action.examNoSubject") }
    }

    // 校验班级在 scope 内
    const scopeError = assertClassInScope(ctx.dataScope, classId)
    if (scopeError) {
      return { success: false, message: t(`action.scopeError.${scopeError}`) }
    }

    const records = safeJsonParse<unknown>(recordsJson, t("action.invalidJson"))

    const parsed = BatchGradeEntryByExamSchema.safeParse({
      examId,
      classId,
      subjectId: exam.subjectId,
      title: exam.title,
      fullScore: exam.totalScore,
      type: formData.get("type") || undefined,
      semester: formData.get("semester") || undefined,
      records,
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidFormData"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const results = await batchCreateGradeRecordsByExam(parsed.data, ctx.userId)
    const ids = results.map((r) => r.gradeRecordId)

    // 更新诊断掌握度 + 采集考试错题（并行，互不阻断）
    await Promise.allSettled(
      results.map(async (r) => {
        const totalScore = parsed.data.records.find(
          (rec) => rec.studentId === r.studentId
        )?.answers.reduce((sum, a) => sum + a.score, 0) ?? 0

        const [, errorBookResult] = await Promise.allSettled([
          updateMasteryFromExamScore(
            r.studentId,
            parsed.data.examId,
            totalScore,
            parsed.data.fullScore,
          ),
          collectFromExamSubmission(r.submissionId, r.studentId),
        ])

        if (errorBookResult.status === "rejected") {
          console.error(
            `[grade-entry] 考试错题采集失败 submission=${r.submissionId}:`,
            errorBookResult.reason,
          )
        }
      }),
    )

    // 通知学生和家长
    try {
      await notifyGradeEntered({
        studentIds: parsed.data.records.map((r) => r.studentId),
        title: parsed.data.title,
        subjectId: parsed.data.subjectId,
        fullScore: parsed.data.fullScore,
      })
    } catch {
      // 通知失败不阻断成绩录入
    }

    // P3-2：批量录入后检测成绩异常（下降超过 10 分 / 10%），异常时通知学生 + 家长
    try {
      await notifyScoreAnomalyIfNeeded({
        studentIds: parsed.data.records.map((r) => r.studentId),
        classId: parsed.data.classId,
        subjectId: parsed.data.subjectId,
        scope: ctx.dataScope,
      })
    } catch {
      // 异常检测失败不阻断成绩录入
    }

    revalidatePath("/teacher/grades")
    return {
      success: true,
      message: t("action.recordsCreated", { count: ids.length }),
      data: ids,
    }
  } catch (e) {
    return handleActionError(e)
  }
}

/**
 * v3-P2-3: 撤销最近一次批量成绩录入。
 * 接收记录 ID 列表，仅允许撤销当前用户自己录入的记录。
 */
export async function undoBatchCreateGradeRecordsAction(
  ids: string[]
): Promise<ActionState<number>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    if (!Array.isArray(ids) || ids.length === 0) {
      return { success: false, message: t("action.noRecordsToUndo") }
    }

    // 防御性：限制单次撤销的记录数量，避免误传超大数组
    if (ids.length > 500) {
      return { success: false, message: t("action.cannotUndoMoreThan") }
    }

    const deletedCount = await undoBatchCreateGradeRecords(ids, ctx.userId)
    revalidatePath("/teacher/grades")
    return {
      success: true,
      message: t("action.recordsUndoneCount", { count: deletedCount }),
      data: deletedCount,
    }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function updateGradeRecordAction(
  id: string,
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    const parsed = UpdateGradeRecordSchema.safeParse({
      title: formData.get("title") || undefined,
      score: formData.get("score") || undefined,
      fullScore: formData.get("fullScore") || undefined,
      type: formData.get("type") || undefined,
      semester: formData.get("semester") || undefined,
      remark: formData.get("remark") || undefined,
      examId: formData.get("examId") || undefined,
    })

    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidFormData"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    await updateGradeRecord(id, parsed.data)
    revalidatePath("/teacher/grades")
    return { success: true, message: t("action.recordUpdated") }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function deleteGradeRecordAction(
  id: string
): Promise<ActionState<string>> {
  try {
    await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    const parsed = DeleteGradeRecordSchema.safeParse({ id })
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidId"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    await deleteGradeRecord(parsed.data.id)
    revalidatePath("/teacher/grades")
    return { success: true, message: t("action.recordDeleted") }
  } catch (e) {
    return handleActionError(e)
  }
}

/**
 * v3-P3-2: 批量删除成绩记录。
 * 使用 inArray 一次性删除，避免 N+1 查询。
 * 限制单次最多删除 500 条记录。
 */
export async function bulkDeleteGradeRecordsAction(
  ids: string[]
): Promise<ActionState<number>> {
  try {
    await requirePermission(Permissions.GRADE_RECORD_MANAGE)
    const t = await getTranslations("grades")

    if (!Array.isArray(ids) || ids.length === 0) {
      return { success: false, message: t("action.noRecordsToDelete") }
    }
    // 防御性：限制单次删除的记录数量
    if (ids.length > 500) {
      return { success: false, message: t("action.cannotDeleteMoreThan") }
    }

    const deletedCount = await bulkDeleteGradeRecords(ids)
    revalidatePath("/teacher/grades")
    return {
      success: true,
      message: t("action.recordsDeletedCount", { count: deletedCount }),
      data: deletedCount,
    }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function getGradeRecordsAction(
  params: GradeQueryParams & { limit?: number; offset?: number }
): Promise<ActionState<PaginatedGradeRecords>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_READ)
    const t = await getTranslations("grades")

    const parsed = GradeQuerySchema.safeParse(params)
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidQuery"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    // P3 修复：对 class_taught scope 校验 classId
    if (parsed.data.classId) {
      const scopeError = assertClassInScope(ctx.dataScope, parsed.data.classId)
      if (scopeError) return { success: false, message: t(`action.scopeError.${scopeError}`) }
    }

    const result = await getGradeRecords({
      ...parsed.data,
      scope: ctx.dataScope,
      currentUserId: ctx.userId,
      limit: params.limit,
      offset: params.offset,
    })
    return { success: true, data: result }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function getClassGradeStatsAction(
  classId: string,
  subjectId?: string,
  examId?: string
): Promise<ActionState<GradeStats | null>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_READ)
    const t = await getTranslations("grades")

    const parsed = ClassGradeStatsQuerySchema.safeParse({ classId, subjectId, examId })
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidQuery"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const scopeError = assertClassInScope(ctx.dataScope, parsed.data.classId)
    if (scopeError) return { success: false, message: t(`action.scopeError.${scopeError}`) }

    const result = await getClassGradeStatsWithMeta(
      parsed.data.classId,
      parsed.data.subjectId,
      parsed.data.examId,
      ctx.dataScope,
      ctx.userId
    )
    return { success: true, data: result?.stats ?? null }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function getStudentGradeSummaryAction(
  studentId: string
): Promise<ActionState<StudentGradeSummary | null>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_READ)
    const t = await getTranslations("grades")

    const parsed = StudentGradeSummaryQuerySchema.safeParse({ studentId })
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidId"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    if (ctx.dataScope.type === "class_members" && ctx.userId !== parsed.data.studentId) {
      return { success: false, message: t("action.ownGradesOnly") }
    }
    if (
      ctx.dataScope.type === "children" &&
      !ctx.dataScope.childrenIds.includes(parsed.data.studentId)
    ) {
      return { success: false, message: t("action.childrenGradesOnly") }
    }

    // P3 修复：传递 scope 到 data-access 层，对 class_taught scope 在数据层校验学生归属
    const summary = await getStudentGradeSummary(parsed.data.studentId, ctx.dataScope)
    return { success: true, data: summary }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function getClassRankingAction(
  classId: string,
  subjectId?: string,
  examId?: string
): Promise<ActionState<ClassRankingItem[]>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_READ)
    const t = await getTranslations("grades")

    const parsed = ClassRankingQuerySchema.safeParse({ classId, subjectId, examId })
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidQuery"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const scopeError = assertClassInScope(ctx.dataScope, parsed.data.classId)
    if (scopeError) return { success: false, message: t(`action.scopeError.${scopeError}`) }

    const ranking = await getClassRanking(
      parsed.data.classId,
      parsed.data.subjectId,
      parsed.data.examId,
      ctx.dataScope,
      ctx.userId
    )
    return { success: true, data: ranking }
  } catch (e) {
    return handleActionError(e)
  }
}

export async function getGradeRecordByIdAction(
  id: string
): Promise<ActionState<GradeRecord | null>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_READ)
    const t = await getTranslations("grades")

    const parsed = GetGradeRecordByIdSchema.safeParse({ id })
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidId"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    const record = await getGradeRecordById(parsed.data.id)

    // Row-level scope check for the fetched record
    if (record) {
      if (ctx.dataScope.type === "class_members" && record.studentId !== ctx.userId) {
        return { success: false, message: t("action.ownRecordsOnly") }
      }
      if (
        ctx.dataScope.type === "children" &&
        !ctx.dataScope.childrenIds.includes(record.studentId)
      ) {
        return { success: false, message: t("action.childrenRecordsOnly") }
      }
      // P3 修复：对 class_taught scope 校验 record.classId 是否在 scope.classIds 中
      if (
        ctx.dataScope.type === "class_taught" &&
        !ctx.dataScope.classIds.includes(record.classId)
      ) {
        return { success: false, message: t("action.taughtClassesOnly") }
      }
    }

    return { success: true, data: record }
  } catch (e) {
    return handleActionError(e)
  }
}

/**
 * 导出成绩单（返回 base64 编码的 Excel）
 */
export async function exportGradesAction(params: {
  classId?: string
  studentId?: string
  subjectId?: string
  examId?: string
  reportType?: "detail" | "class"
}): Promise<ActionState<{ buffer: string; filename: string }>> {
  try {
    const ctx = await requirePermission(Permissions.GRADE_RECORD_READ)
    const t = await getTranslations("grades")

    const parsed = ExportGradesSchema.safeParse(params)
    if (!parsed.success) {
      return {
        success: false,
        message: t("action.invalidFormData"),
        errors: parsed.error.flatten().fieldErrors,
      }
    }

    // v4-P1-12: 支持按 studentId 导出（家长视角）
    // 当提供 studentId 且 scope 为 children 时，校验该学生属于家长的子女
    if (parsed.data.studentId && ctx.dataScope.type === "children") {
      if (!ctx.dataScope.childrenIds.includes(parsed.data.studentId)) {
        return { success: false, message: t("action.exportOwnChildrenOnly") }
      }
      const buffer = await exportStudentGradeRecordsToExcel({
        studentId: parsed.data.studentId,
        subjectId: parsed.data.subjectId,
        scope: ctx.dataScope,
        currentUserId: ctx.userId,
      })
      const filename = t("action.filenameDetail", { date: formatDateForFile() })
      return {
        success: true,
        data: {
          buffer: buffer.toString("base64"),
          filename,
        },
      }
    }

    // classId 必须存在（studentId 分支已返回）
    if (!parsed.data.classId) {
      return { success: false, message: t("action.classIdRequired") }
    }

    // P3 修复：添加 assertClassInScope 校验
    const scopeError = assertClassInScope(ctx.dataScope, parsed.data.classId)
    if (scopeError) return { success: false, message: t(`action.scopeError.${scopeError}`) }

    let buffer: Buffer
    let filename: string

    if (parsed.data.reportType === "class") {
      buffer = await exportClassGradeReportToExcel({
        classId: parsed.data.classId,
        scope: ctx.dataScope,
        currentUserId: ctx.userId,
      })
      filename = t("action.filenameClassReport", { date: formatDateForFile() })
    } else {
      buffer = await exportGradeRecordsToExcel({
        classId: parsed.data.classId,
        subjectId: parsed.data.subjectId,
        examId: parsed.data.examId,
        scope: ctx.dataScope,
        currentUserId: ctx.userId,
      })
      filename = t("action.filenameDetail", { date: formatDateForFile() })
    }

    return {
      success: true,
      data: {
        buffer: buffer.toString("base64"),
        filename,
      },
    }
  } catch (e) {
    return handleActionError(e)
  }
}
