"use client"

import { useEffect, useState } from "react"
import { toast } from "sonner"
import type { ActionState } from "@/shared/types/action-state"

export interface UseActionQueryOptions {
  /** 依赖数组，默认 []。当依赖变化时重新获取。 */
  deps?: ReadonlyArray<unknown>
  /** 是否启用查询，默认 true。为 false 时不发起请求。 */
  enabled?: boolean
  /** 失败时显示的 toast 文案。传 false 则不显示。默认 "Failed to load data"。 */
  errorMessage?: string | false
}

export interface UseActionQueryResult<T> {
  data: T | undefined
  loading: boolean
  error: Error | null
  refetch: () => void
}

/**
 * 通用 Server Action 查询 Hook。
 *
 * 用于替代各组件中重复的 `useEffect + useState(loading) + Action().then().catch().finally()` 模式。
 * 内置竞态防护（通过 ref 跟踪最新请求）。
 *
 * @example
 * const { data, loading } = useActionQuery(
 *   () => getKnowledgePointOptionsAction(),
 *   { deps: [open], enabled: open }
 * )
 */
export function useActionQuery<T>(
  action: () => Promise<ActionState<T>>,
  options: UseActionQueryOptions = {}
): UseActionQueryResult<T> {
  const { deps = [], enabled = true, errorMessage = "Failed to load data" } = options
  const [data, setData] = useState<T | undefined>(undefined)
  const [loading, setLoading] = useState<boolean>(enabled)
  const [error, setError] = useState<Error | null>(null)
  const [refetchCount, setRefetchCount] = useState(0)

  useEffect(() => {
    if (!enabled) return

    let cancelled = false
    setLoading(true)
    setError(null)

    action()
      .then((result) => {
        if (cancelled) return
        if (result.success) {
          setData(result.data)
        } else {
          setError(new Error(result.message ?? "Action failed"))
          if (errorMessage !== false) {
            toast.error(errorMessage)
          }
        }
      })
      .catch((err: unknown) => {
        if (cancelled) return
        setError(err instanceof Error ? err : new Error(String(err)))
        if (errorMessage !== false) {
          toast.error(errorMessage)
        }
      })
      .finally(() => {
        if (!cancelled) setLoading(false)
      })

    return () => {
      cancelled = true
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [...deps, refetchCount])

  const refetch = () => setRefetchCount((c) => c + 1)

  return { data, loading, error, refetch }
}
