import { createId } from "@paralleldrive/cuid2"
import { isRecord } from "@/shared/lib/type-guards"
import type { ExamNode } from "../components/assembly/selected-question-list"

/**
 * Normalize raw exam structure data into typed `ExamNode[]`.
 *
 * - Validates each node's shape at runtime (type guard pattern, no `as`).
 * - Ensures every node has a unique id (generates one if missing or duplicate).
 * - Recursively normalizes group children.
 * - Returns `[]` for non-array input.
 *
 * Used by the exam build page to convert persisted `exam.structure` (unknown
 * JSON from DB) into a typed tree before passing to `<ExamAssembly />`.
 */
export function normalizeStructure(nodes: unknown): ExamNode[] {
  const seen = new Set<string>()

  const normalize = (raw: unknown[]): ExamNode[] => {
    return raw
      .map((n): ExamNode | null => {
        if (!isRecord(n)) return null
        const type = n.type
        if (type !== "section" && type !== "group" && type !== "question") return null

        let id = typeof n.id === "string" && n.id.length > 0 ? n.id : createId()
        while (seen.has(id)) id = createId()
        seen.add(id)

        if (type === "section") {
          return {
            id,
            type: "section",
            title: typeof n.title === "string" ? n.title : undefined,
            level: typeof n.level === "number" ? n.level : undefined,
            children: normalize(Array.isArray(n.children) ? n.children : []),
          } satisfies ExamNode
        }

        if (type === "group") {
          return {
            id,
            type: "group",
            title: typeof n.title === "string" ? n.title : undefined,
            instruction: typeof n.instruction === "string" ? n.instruction : undefined,
            children: normalize(Array.isArray(n.children) ? n.children : []),
          } satisfies ExamNode
        }

        if (typeof n.questionId !== "string" || n.questionId.length === 0) return null

        return {
          id,
          type: "question",
          questionId: n.questionId,
          score: typeof n.score === "number" ? n.score : undefined,
        } satisfies ExamNode
      })
      .filter((n): n is ExamNode => n !== null)
  }

  if (!Array.isArray(nodes)) return []
  return normalize(nodes)
}
