"use client"

import { useCallback, useEffect, useRef, useState } from "react"
import { saveHomeworkAnswerAction } from "../actions"

type AutoSaveStatus = "idle" | "saving" | "saved" | "error"

type AnswerMap = Record<string, { answer: unknown } | undefined>

type UseDebouncedAutoSaveOptions = {
  submissionId: string | null
  answers: AnswerMap
  enabled: boolean
  debounceMs?: number
  storageKey?: string
}

type UseDebouncedAutoSaveResult = {
  status: AutoSaveStatus
  lastSavedAt: number | null
  flush: () => Promise<void>
}

/**
 * P2-9: 学生答案自动保存 + 离线缓存
 *
 * - 答案变更后 debounce（默认 3 秒）自动保存到服务端
 * - 同时写入 localStorage 作为离线缓存
 * - 网络异常时标记 error，恢复后自动重试
 * - 组件卸载时 flush 未保存的答案
 */
export function useDebouncedAutoSave({
  submissionId,
  answers,
  enabled,
  debounceMs = 3000,
  storageKey,
}: UseDebouncedAutoSaveOptions): UseDebouncedAutoSaveResult {
  const [status, setStatus] = useState<AutoSaveStatus>("idle")
  const [lastSavedAt, setLastSavedAt] = useState<number | null>(null)
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const pendingRef = useRef<Map<string, unknown>>(new Map())
  const savingRef = useRef(false)
  const lastSavedAnswersRef = useRef<string>("")

  // Persist to localStorage for offline recovery
  const cacheToLocalStorage = useCallback(
    (snapshot: AnswerMap) => {
      if (!storageKey) return
      try {
        const serialized = JSON.stringify({
          submissionId,
          answers: snapshot,
          timestamp: Date.now(),
        })
        window.localStorage.setItem(storageKey, serialized)
      } catch {
        // localStorage may be full or unavailable; silently ignore
      }
    },
    [storageKey, submissionId]
  )

  // Save a batch of pending answers to the server
  const savePending = useCallback(async () => {
    if (!submissionId || savingRef.current) return
    const pending = Array.from(pendingRef.current.entries())
    if (pending.length === 0) return

    savingRef.current = true
    setStatus("saving")

    let allOk = true
    for (const [questionId, answer] of pending) {
      const fd = new FormData()
      fd.set("submissionId", submissionId)
      fd.set("questionId", questionId)
      fd.set("answerJson", JSON.stringify({ answer }))
      const res = await saveHomeworkAnswerAction(null, fd)
      if (!res.success) {
        allOk = false
      }
    }

    savingRef.current = false

    if (allOk) {
      pendingRef.current.clear()
      setStatus("saved")
      setLastSavedAt(Date.now())
    } else {
      setStatus("error")
      // Keep pending items for retry on next change or manual flush
    }
  }, [submissionId])

  // Schedule debounced save when answers change
  useEffect(() => {
    if (!enabled || !submissionId) return

    const currentSnapshot = JSON.stringify(answers)
    if (currentSnapshot === lastSavedAnswersRef.current) return

    // Cache to localStorage immediately (offline safety net)
    cacheToLocalStorage(answers)

    // Collect changed question IDs
    for (const questionId of Object.keys(answers)) {
      const entry = answers[questionId]
      if (entry !== undefined) {
        pendingRef.current.set(questionId, entry.answer)
      }
    }

    // Clear existing timer and set a new one
    if (timerRef.current) {
      clearTimeout(timerRef.current)
    }
    timerRef.current = setTimeout(() => {
      void savePending()
      lastSavedAnswersRef.current = currentSnapshot
    }, debounceMs)

    return () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current)
        timerRef.current = null
      }
    }
  }, [answers, enabled, submissionId, debounceMs, cacheToLocalStorage, savePending])

  // Flush on unmount
  useEffect(() => {
    return () => {
      if (timerRef.current) {
        clearTimeout(timerRef.current)
      }
      // Fire-and-forget final save
      void savePending()
    }
  }, [savePending])

  // Retry on window focus (network may have recovered)
  useEffect(() => {
    if (status !== "error") return
    const handleFocus = () => {
      void savePending()
    }
    window.addEventListener("focus", handleFocus)
    return () => window.removeEventListener("focus", handleFocus)
  }, [status, savePending])

  const flush = useCallback(async () => {
    if (timerRef.current) {
      clearTimeout(timerRef.current)
      timerRef.current = null
    }
    await savePending()
    lastSavedAnswersRef.current = JSON.stringify(answers)
  }, [answers, savePending])

  return { status, lastSavedAt, flush }
}

/**
 * 从 localStorage 恢复离线缓存的答案
 */
export function loadOfflineCache(storageKey: string): AnswerMap | null {
  try {
    const raw = window.localStorage.getItem(storageKey)
    if (!raw) return null
    const parsed = JSON.parse(raw) as { answers?: AnswerMap }
    if (!parsed.answers || typeof parsed.answers !== "object") return null
    return parsed.answers
  } catch {
    return null
  }
}

/**
 * 清除 localStorage 中的离线缓存
 */
export function clearOfflineCache(storageKey: string): void {
  try {
    window.localStorage.removeItem(storageKey)
  } catch {
    // ignore
  }
}
