import { useCallback, useEffect, useRef, useState } from 'react'
import { useOnTabActive } from './useOnTabActive'

interface UseResourceOptions {
  /** Refetch whenever this keep-alive tab path becomes active again. */
  tabPath?: string
  /** Re-run the fetcher when any of these values change (like useEffect deps). */
  deps?: readonly unknown[]
  /** Fetch immediately on mount (default true). */
  immediate?: boolean
}

interface UseResource<T> {
  data: T | null
  loading: boolean
  /** Refetch. Pass `true` to skip the loading flag (silent poll refresh). */
  reload: (silent?: boolean) => Promise<void>
}

/**
 * Load-on-mount data with a loading flag, a manual/tab-active refetch, and a
 * request-id race guard that drops stale responses (so a slow earlier fetch
 * never overwrites a newer one). Errors propagate to the axios interceptor,
 * matching every page's existing swallow-and-toast behaviour.
 *
 * `fetcher` returns the already-unwrapped value (call `.then(r => r.data)` or
 * combine several requests with Promise.all before resolving).
 */
export function useResource<T>(
  fetcher: () => Promise<T>,
  options: UseResourceOptions = {},
): UseResource<T> {
  const { tabPath, deps = [], immediate = true } = options

  const [data, setData] = useState<T | null>(null)
  const [loading, setLoading] = useState(immediate)

  const fetcherRef = useRef(fetcher)
  fetcherRef.current = fetcher
  const requestId = useRef(0)

  const reload = useCallback(async (silent = false) => {
    const id = ++requestId.current
    if (!silent) setLoading(true)
    try {
      const result = await fetcherRef.current()
      if (id === requestId.current) setData(result)
    } finally {
      if (id === requestId.current && !silent) setLoading(false)
    }
  }, [])

  useEffect(() => {
    if (immediate) void reload()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, deps)

  useOnTabActive(tabPath ?? '', () => {
    if (tabPath) void reload()
  })

  return { data, loading, reload }
}
