/**
 * 题目内容解析纯函数
 *
 * 从 `unknown` 类型的题目内容中安全提取文本、选项、正确答案等。
 * 所有函数均为纯函数，无副作用，便于单测。
 */

export type QuestionOption = {
  id: string
  text: string
  isCorrect?: boolean
}

export const isRecord = (v: unknown): v is Record<string, unknown> =>
  typeof v === "object" && v !== null

export const getQuestionText = (content: unknown): string => {
  if (!isRecord(content)) return ""
  return typeof content.text === "string" ? content.text : ""
}

export const getOptions = (content: unknown): QuestionOption[] => {
  if (!isRecord(content)) return []
  const raw = content.options
  if (!Array.isArray(raw)) return []
  const out: QuestionOption[] = []
  for (const item of raw) {
    if (!isRecord(item)) continue
    const id = typeof item.id === "string" ? item.id : ""
    const text = typeof item.text === "string" ? item.text : ""
    if (!id || !text) continue
    const isCorrect = item.isCorrect === true
    out.push({ id, text, isCorrect })
  }
  return out
}

export const getChoiceCorrectIds = (content: unknown): string[] => {
  return getOptions(content)
    .filter((o): o is QuestionOption & { isCorrect: true } => o.isCorrect === true)
    .map((o) => o.id)
}

export const getJudgmentCorrectAnswer = (content: unknown): boolean | null => {
  if (!isRecord(content)) return null
  return typeof content.correctAnswer === "boolean" ? content.correctAnswer : null
}

export const getTextCorrectAnswers = (content: unknown): string[] => {
  if (!isRecord(content)) return []
  const raw = content.correctAnswer
  if (typeof raw === "string") return [raw]
  if (Array.isArray(raw)) return raw.filter((x): x is string => typeof x === "string")
  return []
}

export type QuestionType = "single_choice" | "multiple_choice" | "judgment" | "text" | string

export type AnswerShape =
  | { answer: string }
  | { answer: boolean }
  | { answer: string[] }
  | { answer: unknown }

export const toAnswerShape = (questionType: QuestionType, v: unknown): AnswerShape => {
  if (questionType === "text") return { answer: typeof v === "string" ? v : "" }
  if (questionType === "judgment") return { answer: typeof v === "boolean" ? v : false }
  if (questionType === "single_choice") return { answer: typeof v === "string" ? v : "" }
  if (questionType === "multiple_choice") {
    return {
      answer: Array.isArray(v) ? v.filter((x): x is string => typeof x === "string") : [],
    }
  }
  return { answer: v }
}

export const parseSavedAnswer = (saved: unknown, questionType: QuestionType): AnswerShape => {
  if (isRecord(saved) && "answer" in saved) {
    return toAnswerShape(questionType, saved.answer)
  }
  return toAnswerShape(questionType, saved)
}

export const extractAnswerValue = (studentAnswer: unknown): unknown => {
  if (isRecord(studentAnswer) && "answer" in studentAnswer) return studentAnswer.answer
  return studentAnswer
}

export const normalizeText = (v: string): string =>
  v.trim().replace(/\s+/g, " ").toLowerCase()

/**
 * 判断题目是否可自动判分（有标准答案）
 */
export const isAutoGradable = (input: {
  questionType: QuestionType
  questionContent: unknown
}): boolean => {
  if (input.questionType === "single_choice" || input.questionType === "multiple_choice") {
    return getChoiceCorrectIds(input.questionContent).length > 0
  }
  if (input.questionType === "judgment") {
    return getJudgmentCorrectAnswer(input.questionContent) !== null
  }
  if (input.questionType === "text") {
    return getTextCorrectAnswers(input.questionContent).length > 0
  }
  return false
}

export type CorrectnessState = "ungraded" | "correct" | "incorrect" | "partial"

/**
 * 计算单题对错状态
 * @returns "correct" | "incorrect" | "partial" | "ungraded"；无标准答案返回 null
 */
export const computeIsCorrect = (input: {
  questionType: QuestionType
  questionContent: unknown
  studentAnswer: unknown
}): boolean | null => {
  const studentVal = extractAnswerValue(input.studentAnswer)

  if (input.questionType === "single_choice") {
    const correct = getChoiceCorrectIds(input.questionContent)
    if (correct.length === 0) return null
    if (typeof studentVal !== "string") return false
    return correct.includes(studentVal)
  }

  if (input.questionType === "multiple_choice") {
    const correct = getChoiceCorrectIds(input.questionContent)
    if (correct.length === 0) return null
    const studentArr = Array.isArray(studentVal)
      ? studentVal.filter((x): x is string => typeof x === "string")
      : []
    const correctSet = new Set(correct)
    const studentSet = new Set(studentArr)
    if (studentSet.size !== correctSet.size) return false
    for (const id of correctSet) {
      if (!studentSet.has(id)) return false
    }
    return true
  }

  if (input.questionType === "judgment") {
    const correct = getJudgmentCorrectAnswer(input.questionContent)
    if (correct === null) return null
    if (typeof studentVal !== "boolean") return false
    return studentVal === correct
  }

  if (input.questionType === "text") {
    const correctAnswers = getTextCorrectAnswers(input.questionContent)
    if (correctAnswers.length === 0) return null
    if (typeof studentVal !== "string") return false
    const normalizedStudent = normalizeText(studentVal)
    return correctAnswers.some((c) => normalizeText(c) === normalizedStudent)
  }

  return null
}

/**
 * 根据分数与满分推断对错状态
 */
export const getCorrectnessState = (input: {
  score: number | null
  maxScore: number
}): CorrectnessState => {
  if (input.score === null) return "ungraded"
  if (input.score === input.maxScore) return "correct"
  if (input.score === 0) return "incorrect"
  return "partial"
}

/**
 * 自动判分输入项
 */
export interface AutoGradableAnswer {
  id: string
  questionId: string
  questionType: QuestionType
  questionContent: unknown
  maxScore: number
  studentAnswer: unknown
  score: number | null
  feedback: string | null
  order: number
}

/**
 * 对未判分的题目应用自动判分
 * - 已有分数（score !== null）的不覆盖
 * - 无标准答案的不判分
 * - 否则按 computeIsCorrect 给满分或 0 分
 */
export const applyAutoGrades = <T extends AutoGradableAnswer>(incoming: T[]): T[] => {
  return incoming.map((a) => {
    if (a.score !== null) return a
    if (!isAutoGradable({ questionType: a.questionType, questionContent: a.questionContent })) {
      return a
    }
    const isCorrect = computeIsCorrect({
      questionType: a.questionType,
      questionContent: a.questionContent,
      studentAnswer: a.studentAnswer,
    })
    if (isCorrect === null) return a
    return { ...a, score: isCorrect ? a.maxScore : 0 }
  })
}

/**
 * 格式化学生答案为可读字符串
 */
export const formatStudentAnswer = (studentAnswer: unknown): string => {
  const v = extractAnswerValue(studentAnswer)
  if (typeof v === "string") return v
  if (typeof v === "boolean") return v ? "True" : "False"
  if (Array.isArray(v)) {
    return v.map((x) => (typeof x === "string" ? x : JSON.stringify(x))).join(", ")
  }
  if (v == null) return "—"
  return JSON.stringify(v)
}
