"use client"

import { useState, useEffect, useCallback, useRef } from "react"
import { toast } from "sonner"
import { useTranslations } from "next-intl"

import { safeActionCall } from "@/shared/lib/action-utils"
import {
  acquireDraftLockAction,
  renewDraftLockAction,
  releaseDraftLockAction,
} from "../actions-lock"
import type { DraftLockStatus } from "../data-access-drafts"

/**
 * P3-6 协同录入锁管理 Hook。
 *
 * 职责：
 * 1. 进入编辑页时自动获取锁
 * 2. 每 3 分钟心跳续期（TTL 为 5 分钟，留足余量）
 * 3. 组件卸载或提交成功时释放锁
 * 4. 锁被他人持有时暴露 conflict 状态供 UI 展示
 *
 * 使用方：成绩批量录入组件，传入 classId+subjectId+type 三元组。
 */
const HEARTBEAT_INTERVAL_MS = 3 * 60 * 1000

interface UseDraftLockParams {
  classId: string
  subjectId: string
  type: string
  /** 是否激活锁机制（如未选择科目/类型时不激活） */
  enabled: boolean
}

interface UseDraftLockReturn {
  status: DraftLockStatus | null
  lockToken: string | null
  isAcquiring: boolean
  isConflict: boolean
  /** 手动重试获取锁（被抢占后用户点击"重试"） */
  retryAcquire: () => Promise<void>
  /** 提交成功后手动释放锁 */
  releaseLock: () => Promise<void>
}

export function useDraftLock(params: UseDraftLockParams): UseDraftLockReturn {
  const { classId, subjectId, type, enabled } = params
  const t = useTranslations("grades")

  const [status, setStatus] = useState<DraftLockStatus | null>(null)
  const [lockToken, setLockToken] = useState<string | null>(null)
  const [isAcquiring, setIsAcquiring] = useState(false)

  // 用 ref 保存最新 token，避免心跳闭包捕获旧值
  const tokenRef = useRef<string | null>(null)
  // 防止卸载时重复 release
  const releasedRef = useRef(false)
  // 防止并发 acquire
  const acquiringRef = useRef(false)

  const isConflict = status !== null && !status.isMine

  const doAcquire = useCallback(async () => {
    if (acquiringRef.current) return
    if (!classId || !subjectId || !type) return

    acquiringRef.current = true
    setIsAcquiring(true)

    const result = await safeActionCall(() =>
      acquireDraftLockAction({ classId, subjectId, type })
    )

    setIsAcquiring(false)
    acquiringRef.current = false

    if (result?.success && result.data?.acquired) {
      const token = result.data.lockToken
      setLockToken(token)
      tokenRef.current = token
      setStatus(result.data.status)
      releasedRef.current = false
    } else if (result?.data) {
      // 锁被他人持有
      setStatus(result.data.status)
      setLockToken(null)
      tokenRef.current = null
    } else {
      toast.error(t("collabLock.acquireFailed"))
    }
  }, [classId, subjectId, type, t])

  // 进入页面 / 参数变化时获取锁
  useEffect(() => {
    if (!enabled) return
    void doAcquire()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [enabled, classId, subjectId, type])

  // 心跳续期
  useEffect(() => {
    if (!enabled || !lockToken) return

    const timer = setInterval(async () => {
      const currentToken = tokenRef.current
      if (!currentToken) return

      const result = await safeActionCall(() =>
        renewDraftLockAction({
          classId,
          subjectId,
          type,
          lockToken: currentToken,
        })
      )

      if (result?.success && result.data?.acquired) {
        const newToken = result.data.lockToken
        setLockToken(newToken)
        tokenRef.current = newToken
        setStatus(result.data.status)
      } else {
        // 续期失败：锁被抢占或过期
        setStatus(result?.data?.status ?? null)
        setLockToken(null)
        tokenRef.current = null
        toast.error(t("collabLock.heartbeatError"))
      }
    }, HEARTBEAT_INTERVAL_MS)

    return () => clearInterval(timer)
  }, [enabled, lockToken, classId, subjectId, type, t])

  // 卸载时释放锁
  useEffect(() => {
    return () => {
      const token = tokenRef.current
      if (!token || releasedRef.current) return
      releasedRef.current = true
      // 使用 sendBeacon 或 fire-and-forget，避免页面卸载时请求被取消
      void releaseDraftLockAction({
        classId,
        subjectId,
        type,
        lockToken: token,
      }).catch(() => {
        // 静默失败：锁会自动过期
      })
    }
  }, [classId, subjectId, type])

  const retryAcquire = useCallback(async () => {
    await doAcquire()
  }, [doAcquire])

  const releaseLock = useCallback(async () => {
    const token = tokenRef.current
    if (!token) return
    releasedRef.current = true
    const result = await safeActionCall(() =>
      releaseDraftLockAction({
        classId,
        subjectId,
        type,
        lockToken: token,
      })
    )
    if (result?.success) {
      setLockToken(null)
      tokenRef.current = null
      setStatus(null)
    }
  }, [classId, subjectId, type])

  return {
    status,
    lockToken,
    isAcquiring,
    isConflict,
    retryAcquire,
    releaseLock,
  }
}
