"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")

    // 并行保存所有待保存答案，单个失败不影响其他答案
    const results = await Promise.allSettled(
      pending.map(([questionId, answer]) => {
        const fd = new FormData()
        fd.set("submissionId", submissionId)
        fd.set("questionId", questionId)
        fd.set("answerJson", JSON.stringify({ answer }))
        return saveHomeworkAnswerAction(null, fd)
      })
    )

    savingRef.current = false

    // 收集失败的 questionId 以便重试
    const failedQuestionIds: string[] = []
    results.forEach((res, idx) => {
      if (res.status !== "fulfilled" || !res.value.success) {
        failedQuestionIds.push(pending[idx][0])
      }
    })

    if (failedQuestionIds.length === 0) {
      pendingRef.current.clear()
      setStatus("saved")
      setLastSavedAt(Date.now())
    } else {
      setStatus("error")
      // 仅保留失败的项用于重试，移除已成功的项
      const newPending = new Map<string, unknown>()
      for (const qid of failedQuestionIds) {
        const ans = pendingRef.current.get(qid)
        if (ans !== undefined) newPending.set(qid, ans)
      }
      pendingRef.current = newPending
    }
  }, [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)
      }
      // 注意：此处无法使用 navigator.sendBeacon，因为保存逻辑调用的是
      // Next.js Server Action（基于 fetch 的 RPC），而非简单的 POST 请求。
      // sendBeacon 仅支持发送原始 body，无法携带 Server Action 所需的
      // 特定 headers 和编码格式。因此采用 fire-and-forget 方式触发最后的
      // 保存，并依赖 localStorage 离线缓存作为兜底（下次进入页面会恢复）。
      // 真正的可靠 flush 由 handleSubmit 在提交前调用 autoSave.flush() 保证。
      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
  }
}
