import { createId } from "@paralleldrive/cuid2"
import type { JSONContent } from "@tiptap/react"
import type {
  EditorDoc,
  EditorQuestion,
  EditorStructureNode,
  RichQuestionContent,
  RichQuestionType,
} from "./exam-rich-editor-types"
import { toRichQuestionType } from "./exam-rich-editor-types"

const extractText = (node: JSONContent | undefined): string => {
  if (!node) return ""
  if (node.type === "text") return node.text ?? ""
  // 硬换行节点(Shift+Enter):插入换行符
  if (node.type === "hardBreak") return "\n"
  // 段落节点:提取内部文本并在末尾补换行符,保留多段落排版
  // (调用方通常 .trim(),不会受末尾多余 \n 影响)
  if (node.type === "paragraph") {
    const inner = Array.isArray(node.content)
      ? node.content.map(extractText).join("")
      : ""
    return inner + "\n"
  }
  if (Array.isArray(node.content)) return node.content.map(extractText).join("")
  return ""
}

const collectBlanks = (nodes: JSONContent[]): Array<{ id: string }> => {
  const blanks: Array<{ id: string }> = []
  let i = 0
  const walk = (n: JSONContent) => {
    if (n.type === "blank") {
      i += 1
      blanks.push({ id: String(i) })
    }
    if (Array.isArray(n.content)) n.content.forEach(walk)
  }
  nodes.forEach(walk)
  return blanks
}

const collectImages = (
  nodes: JSONContent[]
): Array<{ fileId: string; url: string; alt?: string }> => {
  const imgs: Array<{ fileId: string; url: string; alt?: string }> = []
  const walk = (n: JSONContent) => {
    if (n.type === "image" && n.attrs) {
      const fileId =
        typeof n.attrs.fileId === "string" ? n.attrs.fileId : ""
      const url = typeof n.attrs.src === "string" ? n.attrs.src : ""
      if (fileId && url)
        imgs.push({
          fileId,
          url,
          alt: typeof n.attrs.alt === "string" ? n.attrs.alt : undefined,
        })
    }
    if (Array.isArray(n.content)) n.content.forEach(walk)
  }
  nodes.forEach(walk)
  return imgs
}

/** 选择题类型:只有这些类型才会把列表解析为选项 */
const CHOICE_TYPES = new Set(["single_choice", "multiple_choice", "judgment"])

const parseOptions = (
  nodes: JSONContent[],
  questionType: RichQuestionType
): Array<{ id: string; text: string; isCorrect?: boolean }> => {
  // 只有选择题才解析选项,填空/简答/复合题的列表保持为普通文本
  if (!CHOICE_TYPES.has(questionType)) return []
  const options: Array<{ id: string; text: string; isCorrect?: boolean }> = []
  const seenIds = new Set<string>()
  for (const n of nodes) {
    if (n.type === "orderedList" || n.type === "bulletList") {
      if (Array.isArray(n.content)) {
        n.content.forEach((item, idx) => {
          const text = extractText(item).trim()
          const match = text.match(/^([A-Z])[.、)]\s*(.+)$/)
          const id = match ? match[1]! : String.fromCharCode(65 + idx)
          // 同一题目内选项 id 去重,避免多个列表合并后出现重复 "A"
          if (seenIds.has(id)) return
          seenIds.add(id)
          options.push({ id, text: match ? match[2]! : text })
        })
      }
    }
  }
  return options
}

const buildQuestion = (qb: JSONContent): EditorQuestion => {
  const attrs = qb.attrs ?? {}
  const id =
    typeof attrs.questionId === "string" && attrs.questionId
      ? attrs.questionId
      : createId()
  const type = toRichQuestionType(attrs.type, "single_choice")
  const score = typeof attrs.score === "number" ? attrs.score : 0
  const inner = qb.content ?? []

  // 分离出嵌套的 questionBlock(复合题的子题)、选项列表、图片、普通文本
  const subQuestions: Array<{ id: string; text: string; answer?: string; score?: number }> = []
  const nonQuestionBlocks = inner.filter((n) => {
    if (n.type === "questionBlock") {
      const sub = buildQuestion(n)
      const subText = sub.content.text
      const subOptions = sub.content.options
        ?.map((o) => `${o.id}. ${o.text}`)
        .join("\n")
      const fullText = [subText, subOptions].filter(Boolean).join("\n")
      subQuestions.push({
        id: sub.id,
        text: fullText || "",
        score: sub.score,
      })
      return false
    }
    return true
  })

  // 选择题:过滤掉列表(列表作为选项单独处理)
  // 非选择题:保留列表内容在文本中(列表是题干的一部分)
  const isChoice = CHOICE_TYPES.has(type)
  const textNodes = isChoice
    ? nonQuestionBlocks.filter(
        (n) =>
          n.type !== "orderedList" &&
          n.type !== "bulletList" &&
          n.type !== "image"
      )
    : nonQuestionBlocks.filter((n) => n.type !== "image")
  const text = extractText({ type: "doc", content: textNodes })
  const options = parseOptions(nonQuestionBlocks, type)
  const blanks = collectBlanks(nonQuestionBlocks)
  const images = collectImages(nonQuestionBlocks)
  const content: RichQuestionContent = { text: text.trim() }
  if (options.length > 0) content.options = options
  if (blanks.length > 0) content.blanks = blanks
  if (images.length > 0) content.images = images
  if (subQuestions.length > 0) content.subQuestions = subQuestions
  return { id, type, score, content }
}

/** 统计结构节点的题目数和总分(递归) */
const computeStats = (node: EditorStructureNode): { count: number; score: number } => {
  if (node.type === "question") {
    return { count: 1, score: node.score ?? 0 }
  }
  let count = 0
  let score = 0
  for (const child of node.children ?? []) {
    const stats = computeStats(child)
    count += stats.count
    score += stats.score
  }
  return { count, score }
}

/**
 * 递归构建结构树:支持 sectionBlock(分卷) / groupBlock(大题) / questionBlock(题目) 嵌套。
 * 返回结构节点和提取出的所有题目(扁平列表)。
 */
const buildStructureNode = (
  block: JSONContent,
  questions: EditorQuestion[]
): EditorStructureNode | null => {
  if (block.type === "sectionBlock") {
    const title =
      typeof block.attrs?.title === "string" ? block.attrs.title : ""
    const level =
      typeof block.attrs?.level === "number" ? block.attrs.level : 1
    const children: EditorStructureNode[] = []
    for (const inner of block.content ?? []) {
      const child = buildStructureNode(inner, questions)
      if (child) children.push(child)
    }
    const node: EditorStructureNode = {
      id: createId(),
      type: "section",
      title,
      level,
      children,
    }
    const stats = computeStats(node)
    node.questionCount = stats.count
    node.totalScore = stats.score
    return node
  }

  if (block.type === "groupBlock") {
    const title =
      typeof block.attrs?.title === "string" ? block.attrs.title : ""
    const instruction =
      typeof block.attrs?.instruction === "string"
        ? block.attrs.instruction
        : ""
    const children: EditorStructureNode[] = []
    for (const inner of block.content ?? []) {
      const child = buildStructureNode(inner, questions)
      if (child) children.push(child)
    }
    const node: EditorStructureNode = {
      id: createId(),
      type: "group",
      title,
      instruction,
      children,
    }
    const stats = computeStats(node)
    node.questionCount = stats.count
    node.totalScore = stats.score
    return node
  }

  if (block.type === "questionBlock") {
    const q = buildQuestion(block)
    questions.push(q)
    return {
      id: createId(),
      type: "question",
      questionId: q.id,
      score: q.score,
    }
  }

  return null
}

/**
 * 将 Tiptap 编辑器文档(JSONContent)转换为试卷结构(EditorDoc)。
 * 支持 sectionBlock(分卷) / groupBlock(大题) / questionBlock(题目) 任意嵌套。
 */
export const editorDocToStructure = (
  doc: JSONContent,
  title: string
): EditorDoc => {
  const questions: EditorQuestion[] = []
  const structure: EditorStructureNode[] = []
  const topBlocks = doc.content ?? []

  for (const block of topBlocks) {
    const node = buildStructureNode(block, questions)
    if (node) structure.push(node)
  }

  return { title, questions, structure }
}
