"use server"

import { revalidatePath } from "next/cache"
import { getTranslations } from "next-intl/server"
import type { ActionState } from "@/shared/types/action-state"
import { requirePermission, PermissionDeniedError } from "@/shared/lib/auth-guard"
import { Permissions } from "@/shared/types/permissions"
import { z } from "zod"
import {
  handleActionError,
  safeJsonParse,
} from "@/shared/lib/action-utils"
import { trackExamEvent } from "@/shared/lib/track-event"
import {
  deleteExamById,
  duplicateExam,
  getExamCreatorId,
  getExamGrades,
  getExamPreview,
  getExamSubjects,
  getExamsByGradeId,
  persistAiGeneratedExamDraft,
  persistExamDraft,
  resolveSubjectGradeNames,
  updateExamWithQuestions,
} from "./data-access"
import {
  AiQuestionSchema,
  generateAiPreviewData,
  loadAiDraftQuestionsAndStructure,
  regenerateAiQuestionByInstruction,
} from "./ai-pipeline"
import type {
  AiPreviewData,
  AiRewriteQuestionData,
} from "./ai-pipeline"
import type { GradeExamsResult } from "./types"
import {
  failState,
  getStringValue,
  invalidFormState,
  parseExamModeConfig,
  prepareExamCreateContext,
  successState,
} from "./actions-helpers"

// Re-export 从拆分文件迁移的类型导出，保持外部 import 路径不变
// 注意：Next.js 16 禁止在 "use server" 文件中 re-export 值（仅允许 async 函数导出），
// autoMarkExamAction / createExamFromRichEditorAction / updateExamFromRichEditorAction
// 的值 re-export 已移除，调用方直接从源文件 import。
export type { AutoMarkResult } from "./ai-pipeline/auto-mark"
export type { AiPreviewData, AiRewriteQuestionData } from "./ai-pipeline"

const ExamCreateSchema = z.object({
  title: z.string().min(1),
  subject: z.string().min(1),
  grade: z.string().min(1),
  difficulty: z.coerce.number().int().min(1).max(5),
  totalScore: z.coerce.number().int().min(1),
  durationMin: z.coerce.number().int().min(1),
  scheduledAt: z.string().optional().nullable(),
  questions: z
    .array(
      z.object({
        id: z.string(),
        score: z.coerce.number().int().min(0),
      })
    )
    .optional(),
})

const prepareAiPreviewRequest = async (input: {
  title?: string
  subject?: string
  grade?: string
  difficulty?: number
  totalScore?: number
  durationMin?: number
  aiSourceText: string
  aiQuestionCount?: number
  aiProviderId?: string
}) => {
  const resolvedNames = await resolveSubjectGradeNames({
    subjectId: input.subject,
    gradeId: input.grade,
  })
  const title = input.title && input.title.trim().length > 0 ? input.title : "AI Exam"
  const subjectName = input.subject ? resolvedNames.subjectName ?? input.subject : undefined
  const gradeName = input.grade ? resolvedNames.gradeName ?? input.grade : undefined
  return {
    title,
    subject: subjectName,
    grade: gradeName,
    difficulty: input.difficulty ?? 3,
    totalScore: input.totalScore ?? 100,
    durationMin: input.durationMin ?? 90,
    questionCount: input.aiQuestionCount,
    sourceText: input.aiSourceText,
    aiProviderId: input.aiProviderId,
  }
}

const parseRegenerateAiQuestionInput = (
  formData: FormData,
  t: Awaited<ReturnType<typeof getTranslations>>
):
  | {
    ok: true
    instruction: string
    aiProviderId?: string
    sourceText?: string
    originalQuestion: z.infer<typeof AiQuestionSchema>
  }
  | { ok: false; state: ActionState<AiRewriteQuestionData> } => {
  const instruction = getStringValue(formData, "instruction")?.trim()
  const aiProviderId = getStringValue(formData, "aiProviderId")?.trim()
  const sourceText = getStringValue(formData, "sourceText")?.trim()
  const questionJson = getStringValue(formData, "questionJson")
  if (!instruction) {
    return { ok: false, state: failState<AiRewriteQuestionData>(t("enterRewriteInstruction")) }
  }
  if (!questionJson) {
    return { ok: false, state: failState<AiRewriteQuestionData>(t("noSelectedQuestion")) }
  }
  try {
    const parsedQuestion = JSON.parse(questionJson) as unknown
    const validatedQuestion = AiQuestionSchema.safeParse(parsedQuestion)
    if (!validatedQuestion.success) {
      return { ok: false, state: failState<AiRewriteQuestionData>(t("questionFormatInvalid")) }
    }
    return {
      ok: true,
      instruction,
      aiProviderId,
      sourceText,
      originalQuestion: validatedQuestion.data,
    }
  } catch {
    return { ok: false, state: failState<AiRewriteQuestionData>(t("questionFormatInvalid")) }
  }
}

export async function createExamAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    const ctx = await requirePermission(Permissions.EXAM_CREATE)

    const rawQuestionsValue = formData.get("questionsJson")
    const rawQuestions = typeof rawQuestionsValue === "string" ? rawQuestionsValue : null

    const parsed = ExamCreateSchema.safeParse({
      title: getStringValue(formData, "title"),
      subject: getStringValue(formData, "subject"),
      grade: getStringValue(formData, "grade"),
      difficulty: getStringValue(formData, "difficulty"),
      totalScore: getStringValue(formData, "totalScore"),
      durationMin: getStringValue(formData, "durationMin"),
      scheduledAt: getStringValue(formData, "scheduledAt") ?? null,
      questions: rawQuestions ? safeJsonParse(rawQuestions, "题目数据格式无效") : [],
    })

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error, { useFirstMessage: false })
    }

    const input = parsed.data
    const context = await prepareExamCreateContext({
      subject: input.subject,
      grade: input.grade,
      difficulty: input.difficulty,
      totalScore: input.totalScore,
      durationMin: input.durationMin,
      scheduledAt: input.scheduledAt,
    })
    const description = context.buildDescription()

    try {
      await persistExamDraft({
        examId: context.examId,
        title: input.title,
        creatorId: ctx.userId,
        subjectId: input.subject,
        gradeId: input.grade,
        scheduledAt: context.scheduled,
        description,
        examModeConfig: parseExamModeConfig(formData),
      })
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<string>(t("dbCreateFailed"))
    }

    revalidatePath("/teacher/exams/all")

    return successState(context.examId, t("createdSuccess"))
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    return handleActionError(error)
  }
}

const AiExamCreateSchema = ExamCreateSchema.extend({
  aiSourceText: z.string().optional(),
  aiQuestionCount: z.coerce.number().int().min(1).max(200).optional(),
  aiProviderId: z.string().min(1).optional(),
})

const AiExamPreviewSchema = z.object({
  title: z.string().optional(),
  subject: z.string().optional(),
  grade: z.string().optional(),
  difficulty: z.coerce.number().int().min(1).max(5).optional(),
  totalScore: z.coerce.number().int().min(1).optional(),
  durationMin: z.coerce.number().int().min(1).optional(),
  aiSourceText: z.string().min(1),
  aiQuestionCount: z.coerce.number().int().min(1).max(200).optional(),
  aiProviderId: z.string().min(1).optional(),
})

export async function createAiExamAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    const ctx = await requirePermission(Permissions.EXAM_AI_GENERATE)

    const rawQuestionsValue = formData.get("questionsJson")
    const rawQuestions = typeof rawQuestionsValue === "string" ? rawQuestionsValue : null
    const rawAiQuestionsValue = formData.get("aiQuestionsJson")
    const rawAiQuestions = typeof rawAiQuestionsValue === "string" ? rawAiQuestionsValue : null
    const rawStructureValue = formData.get("structureJson")
    const rawStructure = typeof rawStructureValue === "string" ? rawStructureValue : null
    const aiSourceTextRaw = formData.get("aiSourceText")
    const aiQuestionCountRaw = formData.get("aiQuestionCount")
    const aiProviderIdRaw = formData.get("aiProviderId")

    const parsed = AiExamCreateSchema.safeParse({
      title: getStringValue(formData, "title"),
      subject: getStringValue(formData, "subject"),
      grade: getStringValue(formData, "grade"),
      difficulty: getStringValue(formData, "difficulty"),
      totalScore: getStringValue(formData, "totalScore"),
      durationMin: getStringValue(formData, "durationMin"),
      scheduledAt: getStringValue(formData, "scheduledAt") ?? null,
      questions: rawQuestions ? safeJsonParse(rawQuestions, "题目数据格式无效") : [],
      aiSourceText: typeof aiSourceTextRaw === "string" ? aiSourceTextRaw.trim() : undefined,
      aiQuestionCount: typeof aiQuestionCountRaw === "string" && aiQuestionCountRaw.trim().length > 0
        ? aiQuestionCountRaw
        : undefined,
      aiProviderId: typeof aiProviderIdRaw === "string" && aiProviderIdRaw.trim().length > 0
        ? aiProviderIdRaw
        : undefined,
    })

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error)
    }

    const input = parsed.data
    if (!rawAiQuestions && !input.aiSourceText) {
      return failState<string>(t("analyzeFirst"))
    }
    const context = await prepareExamCreateContext({
      subject: input.subject,
      grade: input.grade,
      difficulty: input.difficulty,
      totalScore: input.totalScore,
      durationMin: input.durationMin,
      scheduledAt: input.scheduledAt,
    })

    const aiDraftResult = await loadAiDraftQuestionsAndStructure({
      rawAiQuestions,
      rawStructure,
      title: input.title,
      subject: context.subjectName,
      grade: context.gradeName,
      difficulty: input.difficulty,
      totalScore: input.totalScore,
      durationMin: input.durationMin,
      aiSourceText: input.aiSourceText,
      aiQuestionCount: input.aiQuestionCount,
      aiProviderId: input.aiProviderId,
    })
    if (!aiDraftResult.ok) {
      return failState<string>(aiDraftResult.message)
    }
    const { generated, structure } = aiDraftResult

    const questionCount = generated.length
    const description = context.buildDescription({ questionCount })

    try {
      await persistAiGeneratedExamDraft({
        examId: context.examId,
        title: input.title,
        creatorId: ctx.userId,
        subjectId: input.subject,
        gradeId: input.grade,
        scheduledAt: context.scheduled,
        description,
        structure,
        generated,
        examModeConfig: parseExamModeConfig(formData),
      })
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<string>(t("dbCreateFailed"))
    }

    revalidatePath("/teacher/exams/all")

    // V3-4: 埋点监控（AI 生成考试）
    await trackExamEvent("exam.ai_generated", {
      userId: ctx.userId,
      targetId: context.examId,
      properties: {
        aiSourceText: input.aiSourceText?.length ?? 0,
        aiQuestionCount: input.aiQuestionCount,
      },
    })

    return successState(context.examId, t("createdSuccess"))
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    return handleActionError(error)
  }
}

export async function previewAiExamAction(
  prevState: ActionState<AiPreviewData> | null,
  formData: FormData
): Promise<ActionState<AiPreviewData>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    await requirePermission(Permissions.EXAM_AI_GENERATE)

    const aiSourceTextRaw = formData.get("aiSourceText")
    const aiQuestionCountRaw = formData.get("aiQuestionCount")
    const aiProviderIdRaw = formData.get("aiProviderId")

    const sourceText = typeof aiSourceTextRaw === "string" ? aiSourceTextRaw.trim() : ""
    if (!sourceText) {
      return failState<AiPreviewData>(t("pasteSourceFirst"), {
        aiSourceText: [t("pasteSourceFirst")],
      })
    }

    const parsed = AiExamPreviewSchema.safeParse({
      title: getStringValue(formData, "title"),
      subject: getStringValue(formData, "subject"),
      grade: getStringValue(formData, "grade"),
      difficulty: getStringValue(formData, "difficulty"),
      totalScore: getStringValue(formData, "totalScore"),
      durationMin: getStringValue(formData, "durationMin"),
      aiSourceText: sourceText,
      aiQuestionCount: typeof aiQuestionCountRaw === "string" && aiQuestionCountRaw.trim().length > 0
        ? aiQuestionCountRaw
        : undefined,
      aiProviderId: typeof aiProviderIdRaw === "string" && aiProviderIdRaw.trim().length > 0
        ? aiProviderIdRaw
        : undefined,
    })

    if (!parsed.success) {
      return invalidFormState<AiPreviewData>(parsed.error)
    }

    const input = parsed.data
    const previewRequest = await prepareAiPreviewRequest(input)
    const aiDraft = await generateAiPreviewData(previewRequest)
    if (!aiDraft.ok) {
      return failState<AiPreviewData>(aiDraft.message)
    }
    return successState({ ...aiDraft.data, rawOutput: aiDraft.rawOutput })
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<AiPreviewData>(error.message)
    }
    return handleActionError(error)
  }
}

export async function regenerateAiQuestionAction(
  prevState: ActionState<AiRewriteQuestionData> | null,
  formData: FormData
): Promise<ActionState<AiRewriteQuestionData>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    await requirePermission(Permissions.EXAM_AI_GENERATE)

    const parsedInput = parseRegenerateAiQuestionInput(formData, t)
    if (!parsedInput.ok) {
      return parsedInput.state
    }
    const { instruction, aiProviderId, sourceText, originalQuestion } = parsedInput

    const originalDifficulty = originalQuestion.difficulty ?? 3
    const originalScore = originalQuestion.score ?? 0

    try {
      const result = await regenerateAiQuestionByInstruction({
        instruction,
        originalQuestion,
        sourceText,
        aiProviderId,
      })
      if (!result.ok) {
        return failState<AiRewriteQuestionData>(result.message)
      }
      return successState({
        type: result.data.type,
        difficulty: result.data.difficulty ?? originalDifficulty,
        score: result.data.score ?? originalScore,
        content: result.data.content,
      })
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<AiRewriteQuestionData>(t("aiQuestionFormatInvalid"))
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<AiRewriteQuestionData>(error.message)
    }
    return handleActionError(error)
  }
}

const ExamUpdateSchema = z.object({
  examId: z.string().min(1),
  questions: z
    .array(
      z.object({
        id: z.string(),
        score: z.coerce.number().int().min(0),
      })
    )
    .optional(),
  structure: z.unknown().optional(),
  status: z.enum(["draft", "published", "archived"]).optional(),
})

export async function updateExamAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    const ctx = await requirePermission(Permissions.EXAM_UPDATE)

    const rawQuestions = formData.get("questionsJson")
    const rawStructure = formData.get("structureJson")
    const rawQuestionsStr = typeof rawQuestions === "string" ? rawQuestions : null
    const rawStructureStr = typeof rawStructure === "string" ? rawStructure : null

    const parsed = ExamUpdateSchema.safeParse({
      examId: formData.get("examId"),
      questions: rawQuestionsStr ? safeJsonParse(rawQuestionsStr, "题目数据格式无效") : undefined,
      structure: rawStructureStr ? safeJsonParse(rawStructureStr, "试卷结构数据格式无效") : undefined,
      status: formData.get("status") ?? undefined,
    })

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error, {
        fallbackMessage: t("invalidUpdateData"),
        useFirstMessage: false,
      })
    }

    const { examId, questions, structure, status } = parsed.data

    // Ownership check: non-admin users can only update their own exams
    if (ctx.dataScope.type !== "all") {
      const creatorId = await getExamCreatorId(examId)
      if (!creatorId || creatorId !== ctx.userId) {
        return failState<string>(t("onlyOwnUpdate"))
      }
    }

    try {
      await updateExamWithQuestions(examId, {
        questions: questions ?? undefined,
        structure,
        status,
      })
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<string>(t("dbUpdateFailed"))
    }

    revalidatePath("/teacher/exams/all")

    // V3-4: 埋点监控
    await trackExamEvent("exam.updated", {
      userId: ctx.userId,
      targetId: examId,
      properties: { hasQuestions: !!questions, hasStructure: !!structure, status },
    })

    return successState(examId, t("updated"))
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    return handleActionError(error)
  }
}

const ExamDeleteSchema = z.object({
  examId: z.string().min(1),
})

export async function deleteExamAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    const ctx = await requirePermission(Permissions.EXAM_DELETE)

    const parsed = ExamDeleteSchema.safeParse({
      examId: formData.get("examId"),
    })

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error, {
        fallbackMessage: t("invalidDeleteData"),
        useFirstMessage: false,
      })
    }

    const { examId } = parsed.data

    // Ownership check: non-admin users can only delete their own exams
    if (ctx.dataScope.type !== "all") {
      const creatorId = await getExamCreatorId(examId)
      if (!creatorId || creatorId !== ctx.userId) {
        return failState<string>(t("onlyOwnDelete"))
      }
    }

    try {
      await deleteExamById(examId)
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<string>(t("dbDeleteFailed"))
    }

    revalidatePath("/teacher/exams/all")

    // V3-4: 埋点监控
    await trackExamEvent("exam.deleted", {
      userId: ctx.userId,
      targetId: examId,
    })

    return successState(examId, t("deleted"))
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    return handleActionError(error)
  }
}

const ExamDuplicateSchema = z.object({
  examId: z.string().min(1),
})

export async function duplicateExamAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    const ctx = await requirePermission(Permissions.EXAM_DUPLICATE)

    const parsed = ExamDuplicateSchema.safeParse({
      examId: formData.get("examId"),
    })

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error, {
        fallbackMessage: t("invalidDuplicateData"),
        useFirstMessage: false,
      })
    }

    const { examId } = parsed.data

    let newExamId: string
    try {
      const duplicatedId = await duplicateExam(examId, ctx.userId)
      if (!duplicatedId) {
        return failState<string>(t("notFound"))
      }
      newExamId = duplicatedId
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<string>(t("dbDuplicateFailed"))
    }

    revalidatePath("/teacher/exams/all")

    // V3-4: 埋点监控
    await trackExamEvent("exam.duplicated", {
      userId: ctx.userId,
      targetId: newExamId,
      properties: { sourceExamId: examId },
    })

    return successState(newExamId, t("duplicated"))
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    return handleActionError(error)
  }
}

export async function getExamPreviewAction(
  examId: string
): Promise<ActionState<{ structure: unknown; questions: Array<{ id: string }> }>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    await requirePermission(Permissions.EXAM_READ)

    try {
      const exam = await getExamPreview(examId)

      if (!exam) {
        return failState<{ structure: unknown; questions: Array<{ id: string }> }>(t("notFound"))
      }
      return successState({
        structure: exam.structure,
        questions: exam.questions,
      })
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<{ structure: unknown; questions: Array<{ id: string }> }>(t("loadPreviewFailed"))
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<{ structure: unknown; questions: Array<{ id: string }> }>(error.message)
    }
    return handleActionError(error)
  }
}

export async function getSubjectsAction(): Promise<ActionState<{ id: string; name: string }[]>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    await requirePermission(Permissions.EXAM_READ)

    try {
      const allSubjects = await getExamSubjects()
      return successState(allSubjects)
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<{ id: string; name: string }[]>(t("loadSubjectsFailed"))
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<{ id: string; name: string }[]>(error.message)
    }
    return handleActionError(error)
  }
}

export async function getGradesAction(): Promise<ActionState<{ id: string; name: string }[]>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    await requirePermission(Permissions.EXAM_READ)

    try {
      const allGrades = await getExamGrades()
      return successState(allGrades)
    } catch (error) {
      console.error("[ExamAction]", error instanceof Error ? error.message : String(error))
      return failState<{ id: string; name: string }[]>(t("loadGradesFailed"))
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<{ id: string; name: string }[]>(error.message)
    }
    return handleActionError(error)
  }
}

/**
 * 年级仪表盘 - 维度3：获取年级下所有考试 + 提交统计。
 */
export async function getExamsByGradeIdAction(
  gradeId: string
): Promise<ActionState<GradeExamsResult>> {
  try {
    const t = await getTranslations("examHomework.exam.actionMessages")
    const ctx = await requirePermission(Permissions.EXAM_READ)

    if (!gradeId || gradeId.trim().length === 0) {
      return failState<GradeExamsResult>(t("invalidGradeId"))
    }

    const result = await getExamsByGradeId({
      gradeId,
      scope: ctx.dataScope,
    })
    return successState(result)
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<GradeExamsResult>(error.message)
    }
    return handleActionError(error)
  }
}
