"use client"

import { useCallback, useDeferredValue, useMemo, useState, useTransition, useEffect, useRef } from "react"
import { useRouter } from "next/navigation"
import { useTranslations } from "next-intl"
import { toast } from "sonner"
import { Eye, FileText } from "lucide-react"

import { Card, CardHeader, CardTitle } from "@/shared/components/ui/card"
import { Button } from "@/shared/components/ui/button"
import { ScrollArea } from "@/shared/components/ui/scroll-area"
import { Dialog, DialogContent, DialogTitle, DialogTrigger } from "@/shared/components/ui/dialog"
import { QuestionBankFilters } from "@/shared/components/question/question-bank-filters"
import type { Question } from "@/modules/questions/types"
import type { QuestionType } from "@/modules/questions/types"
import { updateExamAction } from "@/modules/exams/actions"
import { getQuestionsAction } from "@/modules/questions/actions"
import { StructureEditor } from "./assembly/structure-editor"
import { QuestionBankList } from "./assembly/question-bank-list"
import type { ExamNode } from "./assembly/selected-question-list"
import { ExamPaperPreview } from "./assembly/exam-paper-preview"
import { createId } from "@paralleldrive/cuid2"

const QUESTION_TYPES: readonly QuestionType[] = [
  "single_choice",
  "multiple_choice",
  "text",
  "judgment",
  "composite",
] as const

function isQuestionType(value: string): value is QuestionType {
  return (QUESTION_TYPES as readonly string[]).includes(value)
}

type ExamAssemblyProps = {
  examId: string
  title: string
  subject: string
  grade: string
  difficulty: number
  totalScore: number
  durationMin: number
  initialSelected?: Array<{ id: string; score: number }>
  initialStructure?: ExamNode[] // New prop
  questionOptions: Question[]
}

export function ExamAssembly(props: ExamAssemblyProps) {
  const t = useTranslations("examHomework.exam.build")
  const router = useRouter()
  const [search, setSearch] = useState("")
  const [typeFilter, setTypeFilter] = useState<string>("all")
  const [difficultyFilter, setDifficultyFilter] = useState<string>("all")
  const deferredSearch = useDeferredValue(search)
  
  // Bank state
  const [bankQuestions, setBankQuestions] = useState<Question[]>(props.questionOptions)
  const [page, setPage] = useState(1)
  const [hasMore, setHasMore] = useState(props.questionOptions.length >= 20)
  const [isBankLoading, startBankTransition] = useTransition()

  // Initialize structure state
  const [structure, setStructure] = useState<ExamNode[]>(() => {
    const questionById = new Map<string, Question>()
    for (const q of props.questionOptions) questionById.set(q.id, q)

    const hydrate = (nodes: ExamNode[]): ExamNode[] => {
      return nodes.map((node) => {
        if (node.type === "question") {
          const q = node.questionId ? questionById.get(node.questionId) : undefined
          return { ...node, question: q }
        }
        if (node.type === "group" || node.type === "section") {
          return { ...node, children: hydrate(node.children || []) }
        }
        return node
      })
    }
    
    // Use initialStructure if provided (Server generated or DB stored)
    if (props.initialStructure && props.initialStructure.length > 0) {
      return hydrate(props.initialStructure)
    }

    // Fallback logic removed as Server Component handles initial migration
    return []
  })

  const fetchQuestions = useCallback((reset: boolean = false) => {
    startBankTransition(async () => {
      const nextPage = reset ? 1 : page + 1
      try {
        const difficultyNum = difficultyFilter === 'all' ? undefined : parseInt(difficultyFilter, 10)
        const result = await getQuestionsAction({
          q: deferredSearch,
          type: typeFilter === 'all' ? undefined : (isQuestionType(typeFilter) ? typeFilter : undefined),
          difficulty: difficultyNum === undefined || Number.isNaN(difficultyNum) ? undefined : difficultyNum,
          page: nextPage,
          pageSize: 20
        })

        if (result.success && result.data) {
          const questionsList = result.data.data
          setBankQuestions(prev => {
            if (reset) return questionsList
            // Deduplicate just in case
            const existingIds = new Set(prev.map(q => q.id))
            const newQuestions = questionsList.filter(q => !existingIds.has(q.id))
            return [...prev, ...newQuestions]
          })
          setHasMore(questionsList.length === 20)
          setPage(nextPage)
        }
      } catch (error) {
        console.error("[ExamAssembly]", error instanceof Error ? error.message : String(error))
        toast.error(t("loadQuestionsFailed"))
      }
    })
  }, [deferredSearch, page, startBankTransition, typeFilter, difficultyFilter, t])

  const isFirstRender = useRef(true)

  useEffect(() => {
    if (isFirstRender.current) {
      isFirstRender.current = false
      if (deferredSearch === "" && typeFilter === "all" && difficultyFilter === "all") {
        return
      }
    }
    fetchQuestions(true)
  }, [deferredSearch, typeFilter, difficultyFilter, fetchQuestions])

  // Recursively calculate total score
  const assignedTotal = useMemo(() => {
    const calc = (nodes: ExamNode[]): number => {
      return nodes.reduce((sum, node) => {
        if (node.type === 'question') return sum + (node.score || 0)
        if (node.type === 'group' || node.type === 'section') return sum + calc(node.children || [])
        return sum
      }, 0)
    }
    return calc(structure)
  }, [structure])

  const progress = props.totalScore > 0
    ? Math.min(100, Math.max(0, (assignedTotal / props.totalScore) * 100))
    : 0

  const addedQuestionIds = useMemo(() => {
    const ids = new Set<string>()
    const walk = (nodes: ExamNode[]) => {
      for (const n of nodes) {
        if (n.type === "question" && n.questionId) ids.add(n.questionId)
        if ((n.type === "group" || n.type === "section") && n.children) walk(n.children)
      }
    }
    walk(structure)
    return ids
  }, [structure])

  const handleAdd = (question: Question) => {
    setStructure((prev) => {
      const has = (nodes: ExamNode[]): boolean => {
        return nodes.some((n) => {
          if (n.type === "question") return n.questionId === question.id
          if ((n.type === "group" || n.type === "section") && n.children) return has(n.children)
          return false
        })
      }
      if (has(prev)) return prev

      return [
        ...prev,
        {
          id: createId(),
          type: "question",
          questionId: question.id,
          score: 10,
          question,
        },
      ]
    })
  }

  const handleAddGroup = () => {
    setStructure(prev => [
      ...prev,
      {
        id: createId(),
        type: 'group',
        title: t("newGroup"),
        children: []
      }
    ])
  }

  const handleAddSection = () => {
    setStructure(prev => [
      ...prev,
      {
        id: createId(),
        type: 'section',
        title: t("newSection"),
        level: 1,
        children: []
      }
    ])
  }

  const handleRemove = (id: string) => {
    const removeRecursive = (nodes: ExamNode[]): ExamNode[] => {
      return nodes.filter(n => n.id !== id).map(n => {
        if (n.type === 'group' || n.type === 'section') {
          return { ...n, children: removeRecursive(n.children || []) }
        }
        return n
      })
    }
    setStructure(prev => removeRecursive(prev))
  }

  const handleScoreChange = (id: string, score: number) => {
    const updateRecursive = (nodes: ExamNode[]): ExamNode[] => {
      return nodes.map(n => {
        if (n.id === id) return { ...n, score }
        if (n.type === 'group' || n.type === 'section') return { ...n, children: updateRecursive(n.children || []) }
        return n
      })
    }
    setStructure(prev => updateRecursive(prev))
  }

  const handleGroupTitleChange = (id: string, title: string) => {
    const updateRecursive = (nodes: ExamNode[]): ExamNode[] => {
      return nodes.map(n => {
        if (n.id === id) return { ...n, title }
        if (n.type === 'group' || n.type === 'section') return { ...n, children: updateRecursive(n.children || []) }
        return n
      })
    }
    setStructure(prev => updateRecursive(prev))
  }

  // Helper to extract flat list for DB examQuestions table
  const getFlatQuestions = () => {
    const list: Array<{ id: string; score: number }> = []
    const seen = new Set<string>()
    const traverse = (nodes: ExamNode[]) => {
      nodes.forEach(n => {
        if (n.type === 'question' && n.questionId) {
          if (!seen.has(n.questionId)) {
            seen.add(n.questionId)
            list.push({ id: n.questionId, score: n.score || 0 })
          }
        }
        if (n.type === 'group' || n.type === 'section') {
          traverse(n.children || [])
        }
      })
    }
    traverse(structure)
    return list
  }
  
  // Helper to strip runtime question objects for DB structure storage
  const getCleanStructure = () => {
    type CleanExamNode = Omit<ExamNode, "question"> & { children?: CleanExamNode[] }

    const clean = (nodes: ExamNode[]): CleanExamNode[] => {
      return nodes.map(n => {
        const { question, ...rest } = n
        void question
        if (n.type === 'group' || n.type === 'section') {
          return { ...rest, children: clean(n.children || []) }
        }
        return rest
      })
    }
    return clean(structure)
  }

  const [previewOpen, setPreviewOpen] = useState(false)

  const handleSave = async (formData: FormData) => {
    formData.set("examId", props.examId)
    formData.set("questionsJson", JSON.stringify(getFlatQuestions()))
    formData.set("structureJson", JSON.stringify(getCleanStructure()))

    try {
      const result = await updateExamAction(null, formData)
      if (result.success) {
        toast.success(t("saveSuccess"))
      } else {
        toast.error(result.message || t("saveFailed"))
      }
    } catch (error) {
      console.error("[ExamAssembly]", error instanceof Error ? error.message : String(error))
      toast.error(t("saveFailed"))
    }
  }

  const handlePublish = async (formData: FormData) => {
    formData.set("examId", props.examId)
    formData.set("questionsJson", JSON.stringify(getFlatQuestions()))
    formData.set("structureJson", JSON.stringify(getCleanStructure()))
    formData.set("status", "published")

    try {
      const result = await updateExamAction(null, formData)
      if (result.success) {
        toast.success(t("publishSuccess"))
        router.push("/teacher/exams/all")
      } else {
        toast.error(result.message || t("publishFailed"))
      }
    } catch (error) {
      console.error("[ExamAssembly]", error instanceof Error ? error.message : String(error))
      toast.error(t("publishFailed"))
    }
  }

  return (
    <div className="grid h-[calc(100vh-8rem)] gap-4 lg:grid-cols-12">
      {/* Left: Preview (8 cols) */}
      <Card className="lg:col-span-8 flex flex-col overflow-hidden border-2 border-primary/10 shadow-sm">
        <CardHeader className="bg-muted/30 pb-4 border-b">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-3">
              <CardTitle className="text-lg">{t("examStructure")}</CardTitle>
              <div className="h-4 w-[1px] bg-border mx-1" />
              <div className="flex items-center gap-2 text-sm text-muted-foreground">
                <span className="font-medium text-foreground">{props.subject}</span>
                <span>•</span>
                <span>{props.grade}</span>
                <span>•</span>
                <span>{props.durationMin} {t("minutes")}</span>
              </div>
            </div>
            <div className="flex items-center gap-6">
              <Dialog open={previewOpen} onOpenChange={setPreviewOpen}>
                <DialogTrigger asChild>
                  <Button variant="ghost" size="sm" className="gap-2 text-muted-foreground hover:text-foreground">
                    <Eye className="h-4 w-4" />
                    {t("preview")}
                  </Button>
                </DialogTrigger>
                <DialogContent className="max-w-4xl h-[90vh] flex flex-col p-0 gap-0">
                  <div className="p-4 border-b shrink-0 flex items-center justify-between">
                    <DialogTitle className="text-lg font-semibold tracking-tight">{props.title}</DialogTitle>
                  </div>
                  <div className="flex-1 min-h-0 relative">
                    <ScrollArea className="h-full">
                      <div className="max-w-3xl mx-auto py-8 px-6">
                        <ExamPaperPreview 
                          title={props.title}
                          subject={props.subject}
                          grade={props.grade}
                          durationMin={props.durationMin}
                          totalScore={props.totalScore}
                          nodes={structure}
                        />
                      </div>
                    </ScrollArea>
                  </div>
                </DialogContent>
              </Dialog>

              <div className="flex items-center gap-3 text-sm">
                <div className="flex flex-col items-end">
                  <div className="flex items-baseline gap-1">
                    <span className={`text-lg font-bold ${assignedTotal > props.totalScore ? "text-destructive" : "text-primary"}`}>
                      {assignedTotal}
                    </span>
                    <span className="text-muted-foreground">/ {props.totalScore}</span>
                  </div>
                  <span className="text-[10px] uppercase tracking-wider text-muted-foreground font-medium">{t("totalScore")}</span>
                </div>
                <div className="h-10 w-2 rounded-full bg-secondary overflow-hidden flex flex-col-reverse">
                  <div 
                    className={`w-full transition-all ${
                      assignedTotal > props.totalScore ? "bg-destructive" : "bg-primary"
                    }`} 
                    style={{ height: `${Math.min(progress, 100)}%` }} 
                  />
                </div>
              </div>
            </div>
          </div>
        </CardHeader>
        
        <ScrollArea className="flex-1 bg-muted/5">
          <div className="max-w-4xl mx-auto p-6 space-y-8">
            <StructureEditor 
              items={structure}
              onChange={setStructure}
              onScoreChange={handleScoreChange}
              onGroupTitleChange={handleGroupTitleChange}
              onRemove={handleRemove}
              onAddGroup={handleAddGroup}
              onAddSection={handleAddSection}
            />
          </div>
        </ScrollArea>

        <div className="border-t p-4 bg-background flex gap-3 justify-end items-center shadow-[0_-1px_2px_rgba(0,0,0,0.03)]">
          <div className="mr-auto flex items-center gap-3">
            <span className="text-xs text-muted-foreground">
              {structure.length === 0 ? t("startHint") : t("itemsInStructure", { count: structure.length })}
            </span>
            <Button
              variant="ghost"
              size="sm"
              className="gap-2 text-muted-foreground hover:text-foreground"
              onClick={() => router.push(`/teacher/exams/${props.examId}/edit-rich`)}
              title={t("richEditorHint")}
            >
              <FileText className="h-4 w-4" />
              {t("richEditor")}
            </Button>
          </div>
          <form action={handleSave}>
            <Button variant="outline" size="sm" type="submit" className="w-24">{t("saveDraft")}</Button>
          </form>
          <form action={handlePublish}>
            <Button size="sm" type="submit" className="w-24 bg-green-600 hover:bg-green-700 text-white">{t("publish")}</Button>
          </form>
        </div>
      </Card>

      {/* Right: Question Bank (4 cols) */}
      <Card className="lg:col-span-4 flex flex-col overflow-hidden shadow-sm h-full">
        <CardHeader className="pb-3 space-y-3 border-b bg-muted/10">
          <div className="flex items-center justify-between">
             <CardTitle className="text-base font-semibold">{t("questionBank")}</CardTitle>
             <span className="text-xs text-muted-foreground bg-muted px-2 py-0.5 rounded-full">
               {bankQuestions.length}{hasMore ? "+" : ""} {t("loaded")}
             </span>
          </div>
          <QuestionBankFilters
            search={search}
            onSearchChange={setSearch}
            type={typeFilter}
            onTypeChange={setTypeFilter}
            difficulty={difficultyFilter}
            onDifficultyChange={setDifficultyFilter}
            layout="compact"
          />
        </CardHeader>
        
        <ScrollArea className="flex-1 p-0 bg-muted/5">
          <div className="p-3">
             <QuestionBankList
               questions={bankQuestions}
               onAdd={handleAdd}
               isAdded={(id) => addedQuestionIds.has(id)}
               onLoadMore={() => fetchQuestions(false)}
               hasMore={hasMore}
               isLoading={isBankLoading}
               subject={props.subject}
             />
          </div>
        </ScrollArea>
      </Card>
    </div>
  )
}
