// ============================================================
// useAsyncData / useAsyncMutation — 通用异步数据 Hook
//
// 职责：
//   - 自动竞态处理（仅应用最后一次请求的结果）
//   - 自动错误日志记录
//   - RequestErrorType → 用户可读错误信息映射
//   - 为 use-api.ts 提供基础设施
//
// 用法：
//   const { data, loading, error, refetch } = useAsyncData(
//     () => TaskAPI.getTaskList(params),
//     [page, pageSize],
//     { enabled: isLoggedIn },
//   );
//
//   const { execute, loading, error } = useAsyncMutation(
//     (body) => TaskAPI.submitTask(body),
//     { onSuccess: () => refetchTasks() },
//   );
// ============================================================

import { useState, useEffect, useCallback, useRef } from 'react';
import { RequestError, RequestErrorType } from '@/shared/services/types';
import { logger } from '@/shared/utils/bus';

// ---------- 错误信息映射 ----------

/** RequestErrorType → 用户可读的默认错误信息 */
export function getErrorMessage(err: unknown): string {
   if (err instanceof RequestError) {
      switch (err.type) {
         case RequestErrorType.NETWORK:
            return '网络连接失败，请检查网络';
         case RequestErrorType.TIMEOUT:
            return '请求超时，请稍后重试';
         case RequestErrorType.HTTP:
            return err.message || '服务器响应异常';
         case RequestErrorType.BUSINESS:
            return err.message || '业务处理失败';
         case RequestErrorType.CANCELLED:
            return '请求已取消';
         case RequestErrorType.AUTH_EXPIRED:
            return '登录已过期，请重新登录';
         default:
            return err.message || '未知错误';
      }
   }
   if (err instanceof Error) {
      return err.message || '发生未知错误';
   }
   return '发生未知错误';
}

// ---------- useAsyncData — 数据获取 ----------

export interface UseAsyncDataOptions {
   /** 是否启用请求（false 时不触发 fetch，常用于登录后才请求） */
   enabled?: boolean;
   /** 请求标识（用于日志，如 'task-list'、'models'） */
   label?: string;
}

export interface UseAsyncDataReturn<T> {
   /** 响应数据 */
   data: T | null;
   /** 是否正在加载（含首次请求和后续刷新） */
   loading: boolean;
   /** 错误对象（RequestError 或普通 Error） */
   error: Error | null;
   /** 用户可读的错误信息 */
   errorMessage: string | null;
   /** 手动触发重新请求 */
   refetch: () => void;
}

/**
 * 通用数据获取 Hook。
 *
 * - 当 `deps` 变化或 `refetch()` 调用时自动重新请求
 * - 自动处理竞态条件（仅最后一次请求的结果生效）
 * - `enabled: false` 时不发起请求（适用于需登录后请求的场景）
 */
export function useAsyncData<T>(
   fetcher: (signal: AbortSignal) => Promise<T>,
   deps: unknown[],
   options: UseAsyncDataOptions = {},
): UseAsyncDataReturn<T> {
   const { enabled = true, label } = options;

   const [data, setData] = useState<T | null>(null);
   const [loading, setLoading] = useState(false);
   const [error, setError] = useState<Error | null>(null);

   // 竞态计数器
   const raceRef = useRef(0);
   // 手动刷新触发器
   const [refreshTick, setRefreshTick] = useState(0);
   // 是否已挂载（避免 setState on unmounted）
   const mountedRef = useRef(true);

   const refetch = useCallback(() => {
      setRefreshTick((t) => t + 1);
   }, []);

   useEffect(() => {
      mountedRef.current = true;
      return () => { mountedRef.current = false; };
   }, []);

   useEffect(() => {
      if (!enabled) {
         setData(null);
         setError(null);
         return;
      }

      const raceId = ++raceRef.current;
      let cancelled = false;
      const abortController = new AbortController();

      const run = async () => {
         setLoading(true);
         setError(null);
         try {
            const result = await fetcher(abortController.signal);
            if (!cancelled && raceId === raceRef.current && mountedRef.current) {
               setData(result);
            }
         } catch (err) {
            // 请求被 AbortController 显式取消 → 静默忽略，不设 error 状态
            if (abortController.signal.aborted) return;
            if (!cancelled && raceId === raceRef.current && mountedRef.current) {
               const normalized = err instanceof Error ? err : new Error(String(err));
               setError(normalized);
               // 仅在非取消、非认证过期时记录日志（取消是预期行为，认证过期由拦截器统一处理）
               if (err instanceof RequestError) {
                  if (err.type !== RequestErrorType.CANCELLED && err.type !== RequestErrorType.AUTH_EXPIRED) {
                     logger.warn('request', `${label || 'fetch'} 请求失败`, normalized);
                  }
               } else {
                  logger.warn('request', `${label || 'fetch'} 请求失败`, normalized);
               }
            }
         } finally {
            if (!cancelled && raceId === raceRef.current && mountedRef.current) {
               setLoading(false);
            }
         }
      };

      void run();

      return () => {
         cancelled = true;
         abortController.abort();
      };
      // eslint-disable-next-line react-hooks/exhaustive-deps
   }, [enabled, refreshTick, ...deps]);

   return {
      data,
      loading,
      error,
      errorMessage: error ? getErrorMessage(error) : null,
      refetch,
   };
}

// ---------- useAsyncMutation — 数据变更 ----------

export interface UseAsyncMutationOptions<T, Args extends unknown[]> {
   /** 请求标识（用于日志） */
   label?: string;
   /** 成功回调 */
   onSuccess?: (data: T, ...args: Args) => void;
   /** 失败回调 */
   onError?: (err: Error, ...args: Args) => void;
}

export interface UseAsyncMutationReturn<T, Args extends unknown[]> {
   /** 执行变更 */
   execute: (...args: Args) => Promise<T | undefined>;
   /** 是否正在执行 */
   loading: boolean;
   /** 最近一次错误 */
   error: Error | null;
   /** 用户可读的错误信息 */
   errorMessage: string | null;
   /** 清除错误状态 */
   reset: () => void;
}

/**
 * 通用数据变更 Hook（POST / PUT / DELETE 等）。
 *
 * - 不自动执行，需手动调用 `execute()`
 * - 返回 Promise，调用方可 await 获取结果
 * - 自动错误日志记录
 */
export function useAsyncMutation<T, Args extends unknown[] = []>(
   mutator: (...args: Args) => Promise<T>,
   options: UseAsyncMutationOptions<T, Args> = {},
): UseAsyncMutationReturn<T, Args> {
   const { label, onSuccess, onError } = options;

   const [loading, setLoading] = useState(false);
   const [error, setError] = useState<Error | null>(null);
   const mountedRef = useRef(true);

   useEffect(() => {
      mountedRef.current = true;
      return () => { mountedRef.current = false; };
   }, []);

   const execute = useCallback(
      async (...args: Args): Promise<T | undefined> => {
         setLoading(true);
         setError(null);
         try {
            const result = await mutator(...args);
            if (mountedRef.current) {
               setLoading(false);
            }
            onSuccess?.(result, ...args);
            return result;
         } catch (err) {
            const normalized = err instanceof Error ? err : new Error(String(err));
            if (mountedRef.current) {
               setError(normalized);
               setLoading(false);
            }
            if (err instanceof RequestError) {
               if (err.type !== RequestErrorType.CANCELLED && err.type !== RequestErrorType.AUTH_EXPIRED) {
                  logger.warn('request', `${label || 'mutation'} 执行失败`, normalized);
               }
            } else {
               logger.warn('request', `${label || 'mutation'} 执行失败`, normalized);
            }
            onError?.(normalized, ...args);
            return undefined;
         }
      },
      [mutator, label, onSuccess, onError],
   );

   const reset = useCallback(() => {
      setError(null);
   }, []);

   return {
      execute,
      loading,
      error,
      errorMessage: error ? getErrorMessage(error) : null,
      reset,
   };
}
