import { useState, useEffect, useCallback, useRef } from 'react'

/** 简易 AbortSignal 替代（兼容小程序环境） */
class SimpleAbortSignal {
  private _aborted = false
  get aborted() { return this._aborted }
  abort() { this._aborted = true }
}
class SimpleAbortController {
  signal = new SimpleAbortSignal()
  abort() { this.signal.abort() }
}

export interface RequestState<T = any> {
  /** 请求结果数据 */
  data: T | null
  /** 是否加载中 */
  loading: boolean
  /** 错误信息 */
  error: Error | null
  /** 是否首次加载完成（不管成功或失败） */
  initialized: boolean
}

export interface UseRequestOptions<T = any, P extends any[] = any[]> {
  /** 手动触发模式下需要调用 run 执行 */
  manual?: boolean
  /** 初始数据 */
  defaultData?: T
  /** 请求函数 */
  service?: (...args: P) => Promise<T>
  /** 成功回调 */
  onSuccess?: (data: T, params: P) => void
  /** 失败回调 */
  onError?: (error: Error, params: P) => void
  /** 轮询间隔（毫秒），设置后自动轮询 */
  pollingInterval?: number
  /** 轮询在页面隐藏时暂停，默认 true */
  pollingWhenHidden?: boolean
  /** 防抖延迟（毫秒） */
  debounceInterval?: number
  /** 依赖变化时自动重新请求 */
  refreshDeps?: unknown[]
  /** 请求节流间隔（毫秒） */
  throttleInterval?: number
  /** 缓存 key，相同 key 的请求结果会被缓存 */
  cacheKey?: string
  /** 缓存有效期（毫秒） */
  cacheTime?: number
  /** 重新请求尝试次数 */
  retryCount?: number
  /** 重试延迟（毫秒），默认 1000 */
  retryInterval?: number
}

export interface UseRequestReturn<T = any, P extends any[] = any[]> {
  /** 当前状态 */
  state: RequestState<T>
  /** 请求结果数据（state.data 的快捷访问） */
  data: T | null
  /** 是否加载中（state.loading 的快捷访问） */
  loading: boolean
  /** 错误信息（state.error 的快捷访问） */
  error: Error | null
  /** 是否首次加载完成（state.initialized 的快捷访问） */
  initialized: boolean
  /** 触发请求（manual 模式下） */
  run: (...params: P) => Promise<T | undefined>
  /** 带 loading 的运行 */
  runLoading: (...params: P) => Promise<T | undefined>
  /** 取消请求 */
  cancel: () => void
  /** 刷新（使用上次参数） */
  refresh: () => void
  /** 修改 data（不发起请求） */
  mutate: (data: T | ((prev: T | null) => T)) => void
  /** 当前参数 */
  params: P
}

// 简单缓存
const cache = new Map<string, { data: unknown; expireAt: number }>()

function getCache<T>(key: string): T | null {
  const item = cache.get(key)
  if (!item) return null
  if (Date.now() > item.expireAt) {
    cache.delete(key)
    return null
  }
  return item.data as T
}

function setCache<T>(key: string, data: T, cacheTime: number) {
  cache.set(key, { data, expireAt: Date.now() + cacheTime })
}

/**
 * 请求封装 Hook
 * @param service 请求函数
 * @param options 配置选项
 */
// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useRequest<T = any, P extends any[] = any[]>(
  service: (...args: P) => Promise<T>,
  options: UseRequestOptions<T, P> = {}
): UseRequestReturn<T, P>

// eslint-disable-next-line @typescript-eslint/no-explicit-any
export function useRequest<T = any>(
  service: undefined,
  options: UseRequestOptions<T, unknown[]> = {}
): UseRequestReturn<T, unknown[]>

export function useRequest<T = any, P extends any[] = any[]>(
  service: ((...args: P) => Promise<T>) | undefined,
  options: UseRequestOptions<T, P> = {}
): UseRequestReturn<T, P> {
  const {
    manual = false,
    defaultData,
    onSuccess,
    onError,
    pollingInterval,
    pollingWhenHidden = true,
    debounceInterval,
    refreshDeps = [],
    throttleInterval,
    cacheKey,
    cacheTime = 5 * 60 * 1000,
    retryCount = 0,
    retryInterval = 1000,
  } = options

  const [state, setState] = useState<RequestState<T>>({
    data: defaultData ?? null,
    loading: false,
    error: null,
    initialized: !!defaultData,
  })

  const [params, setParams] = useState<P>([] as unknown as P)

  const serviceRef = useRef(service)
  const onSuccessRef = useRef(onSuccess)
  const onErrorRef = useRef(onError)
  const pollingTimerRef = useRef<ReturnType<typeof setInterval> | null>(null)
  const abortControllerRef = useRef<SimpleAbortController | null>(null)
  const isMountedRef = useRef(true)
  const debounceTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const throttleLastRunRef = useRef(0)

  // 更新 refs
  useEffect(() => {
    serviceRef.current = service
  }, [service])
  useEffect(() => { onSuccessRef.current = onSuccess }, [onSuccess])
  useEffect(() => { onErrorRef.current = onError }, [onError])

  // 清理
  useEffect(() => {
    isMountedRef.current = true
    return () => {
      isMountedRef.current = false
      if (pollingTimerRef.current) clearInterval(pollingTimerRef.current)
      if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current)
      abortControllerRef.current?.abort()
    }
  }, [])

  // 页面可见性处理（使用 Taro 生命周期，兼容小程序环境）
  useEffect(() => {
    if (!pollingInterval || !pollingWhenHidden) return
    // 在小程序中，Taro.useDidShow / useDidHide 仅可在页面组件中使用
    // useRequest 作为通用 hook 无法直接使用这些，因此跳过
    // 如需轮询暂停/恢复能力，可在页面组件中手动调用 cancel / refresh
  }, [pollingInterval, pollingWhenHidden])

  // 依赖刷新 - 使用 useRef 避免闭包过期
  const refreshDepsRef = useRef(refreshDeps)
  refreshDepsRef.current = refreshDeps

  useEffect(() => {
    if (!manual && refreshDepsRef.current.length > 0) {
      refresh()
    }
  }, [...refreshDeps]) // eslint-disable-line

  const run = useCallback(async (...p: P): Promise<T | undefined> => {
    // 防抖
    if (debounceInterval) {
      if (debounceTimerRef.current) clearTimeout(debounceTimerRef.current)
      return new Promise((resolve) => {
        debounceTimerRef.current = setTimeout(async () => {
          const result = await doRequest(...p)
          resolve(result)
        }, debounceInterval)
      })
    }

    // 节流
    if (throttleInterval) {
      const now = Date.now()
      if (now - throttleLastRunRef.current < throttleInterval) {
        return
      }
      throttleLastRunRef.current = now
    }

    return doRequest(...p)
  }, [debounceInterval, throttleInterval]) // eslint-disable-line

  const doRequest = useCallback(async (...p: P): Promise<T | undefined> => {
    if (!serviceRef.current) return

    setParams(p)
    abortControllerRef.current?.abort()
    abortControllerRef.current = new SimpleAbortController()

    // 检查缓存
    if (cacheKey) {
      const cached = getCache<T>(cacheKey)
      if (cached !== null) {
        setState({ data: cached, loading: false, error: null, initialized: true })
        return cached
      }
    }

    setState(prev => ({ ...prev, loading: true, error: null }))

    try {
      let result!: T
      let attempt = 0
      const maxAttempts = retryCount + 1

      while (attempt < maxAttempts) {
        try {
          result = await serviceRef.current(...p)
          break
        } catch (err: unknown) {
          attempt++
          const isAbortError = err instanceof Error && err.message.includes('abort')
          if (attempt >= maxAttempts || isAbortError) {
            throw err
          }
          await new Promise(r => setTimeout(r, retryInterval * attempt))
        }
      }

      if (!isMountedRef.current) return

      // 缓存
      if (cacheKey) {
        setCache(cacheKey, result, cacheTime)
      }

      setState({ data: result, loading: false, error: null, initialized: true })
      onSuccessRef.current?.(result, p)

      // 轮询
      if (pollingInterval && !pollingTimerRef.current) {
        pollingTimerRef.current = setInterval(() => {
          doRequest(...p)
        }, pollingInterval)
      }

      return result
    } catch (err: unknown) {
      if (!isMountedRef.current) return
      const error = err instanceof Error ? err : new Error(String(err))
      setState({ data: null, loading: false, error, initialized: true })
      onErrorRef.current?.(error, p)
      return undefined
    }
  }, [cacheKey, cacheTime, pollingInterval, pollingWhenHidden, retryCount, retryInterval]) // eslint-disable-line

  const runLoading = useCallback(async (...p: P) => {
    if (!serviceRef.current) return
    setParams(p)
    return doRequest(...p)
  }, [doRequest])

  const cancel = useCallback(() => {
    if (pollingTimerRef.current) {
      clearInterval(pollingTimerRef.current)
      pollingTimerRef.current = null
    }
    abortControllerRef.current?.abort()
    setState(prev => ({ ...prev, loading: false }))
  }, [])

  const refresh = useCallback(() => {
    if (params.length > 0) {
      run(...params)
    }
  }, [params, run])

  const mutate = useCallback((data: T | ((prev: T | null) => T)) => {
    setState(prev => ({
      ...prev,
      data: typeof data === 'function' ? (data as (prev: T | null) => T)(prev.data) : data,
    }))
  }, [])

  // 自动执行
  useEffect(() => {
    if (!manual && service) {
      run(...([] as unknown as P))
    }
  }, []) // eslint-disable-line

  return {
    state,
    data: state.data,
    loading: state.loading,
    error: state.error,
    initialized: state.initialized,
    run,
    runLoading,
    cancel,
    refresh,
    mutate,
    params,
  }
}
