"use server"

import { revalidatePath } from "next/cache"
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 { createId } from "@paralleldrive/cuid2"
import {
  buildExamDescription,
  deleteExamById,
  duplicateExam,
  getExamCreatorId,
  getExamGrades,
  getExamPreview,
  getExamSubjects,
  persistAiGeneratedExamDraft,
  persistExamDraft,
  resolveSubjectGradeNames,
  updateExamWithQuestions,
  type ExamModeConfig,
} from "./data-access"
import {
  AiGeneratedStructureSchema,
  AiInsertQuestionSchema,
  AiQuestionSchema,
  generateAiCreateDraftFromSource,
  generateAiPreviewData,
  regenerateAiQuestionByInstruction,
} from "./ai-pipeline"
import type {
  AiGeneratedQuestion,
  AiGeneratedStructureNode,
  AiPreviewData,
  AiRewriteQuestionData,
} from "./ai-pipeline"
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 getStringValue = (formData: FormData, key: string) => {
  const value = formData.get(key)
  return typeof value === "string" ? value : undefined
}

const getBoolValue = (formData: FormData, key: string, fallback = false): boolean => {
  const value = formData.get(key)
  if (typeof value !== "string") return fallback
  return value === "true"
}

const parseExamModeConfig = (formData: FormData): ExamModeConfig => {
  const rawMode = getStringValue(formData, "examMode")
  const examMode: ExamModeConfig["examMode"] =
    rawMode === "timed" || rawMode === "proctored" ? rawMode : "homework"
  const rawDuration = getStringValue(formData, "durationMinutes")
  const durationMinutes = rawDuration && Number.isFinite(Number(rawDuration))
    ? Number(rawDuration)
    : null
  return {
    examMode,
    durationMinutes,
    shuffleQuestions: getBoolValue(formData, "shuffleQuestions", false),
    allowLateStart: getBoolValue(formData, "allowLateStart", false),
    lateStartGraceMinutes: Number(getStringValue(formData, "lateStartGraceMinutes") ?? "0") || 0,
    antiCheatEnabled: getBoolValue(formData, "antiCheatEnabled", false),
  }
}

const failState = <T>(message: string, errors?: Record<string, string[]>): ActionState<T> => ({
  success: false,
  message,
  errors,
})

const successState = <T>(data: T, message?: string): ActionState<T> => ({
  success: true,
  message,
  data,
})

const invalidFormState = <T>(
  error: z.ZodError,
  options?: { fallbackMessage?: string; useFirstMessage?: boolean }
): ActionState<T> => {
  const errors = error.flatten().fieldErrors
  const fallbackMessage = options?.fallbackMessage ?? "Invalid form data"
  const useFirstMessage = options?.useFirstMessage ?? true
  const messages = Object.values(errors).flatMap((items) => items ?? [])
  const firstMessage = messages.find((msg): msg is string => typeof msg === "string" && msg.length > 0)
  return failState<T>(useFirstMessage ? (firstMessage ?? fallbackMessage) : fallbackMessage, errors)
}

const prepareExamCreateContext = async (input: {
  subject: string
  grade: string
  difficulty: number
  totalScore: number
  durationMin: number
  scheduledAt?: string | null
}) => {
  const examId = createId()
  const scheduled = input.scheduledAt || undefined
  const resolvedNames = await resolveSubjectGradeNames({
    subjectId: input.subject,
    gradeId: input.grade,
  })
  const subjectName = resolvedNames.subjectName ?? input.subject
  const gradeName = resolvedNames.gradeName ?? input.grade
  const buildDescription = (options?: { questionCount?: number }) => buildExamDescription({
    subject: subjectName,
    grade: gradeName,
    difficulty: input.difficulty,
    totalScore: input.totalScore,
    durationMin: input.durationMin,
    scheduledAt: scheduled,
    questionCount: options?.questionCount,
  })
  return { examId, scheduled, subjectName, gradeName, buildDescription }
}

const loadAiDraftQuestionsAndStructure = async (input: {
  rawAiQuestions: string | null
  rawStructure: string | null
  title: string
  subject: string
  grade: string
  difficulty: number
  totalScore: number
  durationMin: number
  aiSourceText?: string
  aiQuestionCount?: number
  aiProviderId?: string
}): Promise<
  | { ok: true; generated: AiGeneratedQuestion[]; structure: AiGeneratedStructureNode[] }
  | { ok: false; message: string }
> => {
  if (input.rawAiQuestions) {
    let parsedQuestions: unknown = null
    try {
      parsedQuestions = JSON.parse(input.rawAiQuestions)
    } catch {
      return { ok: false, message: "Invalid AI preview payload" }
    }
    const validated = z.array(AiInsertQuestionSchema).safeParse(parsedQuestions)
    if (!validated.success || validated.data.length === 0) {
      return { ok: false, message: "Invalid AI preview payload" }
    }
    const generated: AiGeneratedQuestion[] = validated.data.map((q) => ({
      id: q.id,
      type: q.type,
      difficulty: q.difficulty,
      score: q.score,
      content: {
        text: q.content.text,
        ...(q.content.options
          ? {
              options: q.content.options.map((opt) => ({
                id: opt.id,
                text: opt.text,
                isCorrect: opt.isCorrect ?? false,
              })),
            }
          : {}),
        ...(q.content.subQuestions ? { subQuestions: q.content.subQuestions } : {}),
      },
    }))
    let structure: AiGeneratedStructureNode[] = []
    if (input.rawStructure) {
      try {
        const parsedStructure = JSON.parse(input.rawStructure)
        const validatedStructure = AiGeneratedStructureSchema.safeParse(parsedStructure)
        if (validatedStructure.success) {
          structure = validatedStructure.data
        } else {
          return { ok: false, message: "Invalid preview structure" }
        }
      } catch {
        return { ok: false, message: "Invalid preview structure" }
      }
    }
    if (structure.length === 0) {
      structure = generated.map((q) => ({
        id: createId(),
        type: "question",
        questionId: q.id,
        score: q.score,
      }))
    }
    return { ok: true, generated, structure }
  }

  const sourceText = input.aiSourceText?.trim()
  if (!sourceText) {
    return { ok: false, message: "Please analyze and preview before creating" }
  }
  const aiDraft = await generateAiCreateDraftFromSource({
    title: input.title,
    subject: input.subject,
    grade: input.grade,
    difficulty: input.difficulty,
    totalScore: input.totalScore,
    durationMin: input.durationMin,
    questionCount: input.aiQuestionCount,
    sourceText,
    aiProviderId: input.aiProviderId,
  })
  if (!aiDraft.ok) {
    return { ok: false, message: aiDraft.message }
  }
  return { ok: true, generated: aiDraft.generated, structure: aiDraft.structure }
}

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
):
  | {
    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>("Please enter rewrite instruction") }
  }
  if (!questionJson) {
    return { ok: false, state: failState<AiRewriteQuestionData>("No selected question data") }
  }
  try {
    const parsedQuestion = JSON.parse(questionJson) as unknown
    const validatedQuestion = AiQuestionSchema.safeParse(parsedQuestion)
    if (!validatedQuestion.success) {
      return { ok: false, state: failState<AiRewriteQuestionData>("Selected question format invalid") }
    }
    return {
      ok: true,
      instruction,
      aiProviderId,
      sourceText,
      originalQuestion: validatedQuestion.data,
    }
  } catch {
    return { ok: false, state: failState<AiRewriteQuestionData>("Selected question format invalid") }
  }
}

export async function createExamAction(
  prevState: ActionState<string> | null,
  formData: FormData
): Promise<ActionState<string>> {
  try {
    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 ? JSON.parse(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("Failed to create exam:", error)
      return failState<string>("Database error: Failed to create exam")
    }

    revalidatePath("/teacher/exams/all")

    return successState(context.examId, "Exam created successfully.")
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    throw 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 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 ? JSON.parse(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>("Please analyze and preview before creating")
    }
    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("Failed to create exam:", error)
      return failState<string>("Database error: Failed to create exam")
    }

    revalidatePath("/teacher/exams/all")

    return successState(context.examId, "Exam created successfully.")
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    throw error
  }
}

export async function previewAiExamAction(
  prevState: ActionState<AiPreviewData> | null,
  formData: FormData
): Promise<ActionState<AiPreviewData>> {
  try {
    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>("Please paste the full exam text first", {
        aiSourceText: ["Please paste the full exam text first"],
      })
    }

    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)
    }
    throw error
  }
}

export async function regenerateAiQuestionAction(
  prevState: ActionState<AiRewriteQuestionData> | null,
  formData: FormData
): Promise<ActionState<AiRewriteQuestionData>> {
  try {
    await requirePermission(Permissions.EXAM_AI_GENERATE)

    const parsedInput = parseRegenerateAiQuestionInput(formData)
    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 {
      return failState<AiRewriteQuestionData>("AI question format invalid")
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<AiRewriteQuestionData>(error.message)
    }
    throw 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 ctx = await requirePermission(Permissions.EXAM_UPDATE)

    const rawQuestions = formData.get("questionsJson")
    const rawStructure = formData.get("structureJson")
    const hasQuestions = typeof rawQuestions === "string"
    const hasStructure = typeof rawStructure === "string"

    const parsed = ExamUpdateSchema.safeParse({
      examId: formData.get("examId"),
      questions: hasQuestions ? JSON.parse(rawQuestions) : undefined,
      structure: hasStructure ? JSON.parse(rawStructure) : undefined,
      status: formData.get("status") ?? undefined,
    })

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error, {
        fallbackMessage: "Invalid update data",
        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>("You can only update exams you created")
      }
    }

    try {
      await updateExamWithQuestions(examId, {
        questions: questions ?? undefined,
        structure,
        status,
      })
    } catch {
      return failState<string>("Database error: Failed to update exam")
    }

    revalidatePath("/teacher/exams/all")

    return successState(examId, "Exam updated")
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    throw 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 ctx = await requirePermission(Permissions.EXAM_DELETE)

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

    if (!parsed.success) {
      return invalidFormState<string>(parsed.error, {
        fallbackMessage: "Invalid delete data",
        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>("You can only delete exams you created")
      }
    }

    try {
      await deleteExamById(examId)
    } catch {
      return failState<string>("Database error: Failed to delete exam")
    }

    revalidatePath("/teacher/exams/all")

    return successState(examId, "Exam deleted")
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<string>(error.message)
    }
    throw 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 ctx = await requirePermission(Permissions.EXAM_DUPLICATE)

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

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

    const { examId } = parsed.data

    let newExamId: string
    try {
      const duplicatedId = await duplicateExam(examId, ctx.userId)
      if (!duplicatedId) {
        return failState<string>("Exam not found")
      }
      newExamId = duplicatedId
    } catch {
      return failState<string>("Database error: Failed to duplicate exam")
    }

    revalidatePath("/teacher/exams/all")

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

export async function getExamPreviewAction(
  examId: string
): Promise<ActionState<{ structure: unknown; questions: Array<{ id: string }> }>> {
  try {
    await requirePermission(Permissions.EXAM_READ)

    try {
      const exam = await getExamPreview(examId)

      if (!exam) {
        return failState<{ structure: unknown; questions: Array<{ id: string }> }>("Exam not found")
      }
      return successState({
        structure: exam.structure,
        questions: exam.questions,
      })
    } catch (error) {
      console.error(error)
      return failState<{ structure: unknown; questions: Array<{ id: string }> }>("Failed to load exam preview")
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<{ structure: unknown; questions: Array<{ id: string }> }>(error.message)
    }
    throw error
  }
}

export async function getSubjectsAction(): Promise<ActionState<{ id: string; name: string }[]>> {
  try {
    await requirePermission(Permissions.EXAM_READ)

    try {
      const allSubjects = await getExamSubjects()
      return successState(allSubjects)
    } catch (error) {
      console.error("Failed to fetch subjects:", error)
      return failState<{ id: string; name: string }[]>("Failed to load subjects")
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<{ id: string; name: string }[]>(error.message)
    }
    throw error
  }
}

export async function getGradesAction(): Promise<ActionState<{ id: string; name: string }[]>> {
  try {
    await requirePermission(Permissions.EXAM_READ)

    try {
      const allGrades = await getExamGrades()
      return successState(allGrades)
    } catch (error) {
      console.error("Failed to fetch grades:", error)
      return failState<{ id: string; name: string }[]>("Failed to load grades")
    }
  } catch (error) {
    if (error instanceof PermissionDeniedError) {
      return failState<{ id: string; name: string }[]>(error.message)
    }
    throw error
  }
}


