import { onMounted, ref, shallowReactive, watch, type Ref } from 'vue';
import { debounce, throttle } from './utils';

// 添加分页响应数据类型
// type PaginationResponse<T = any> = {
//   list?: T[];
//   data?: T[];
//   total: number;
//   current: number;
//   pageSize: number;
// };

type Option<R, P> = {
  /** 是否需要uni.showLoading */
  useUniLoading?: boolean;
  /**
   * 每次 ready 从 false 变为 true 时, 都会自动发起请求
   * 为 false 时，请求永远都不会发出
   */
  ready?: boolean | Ref<boolean>;
  /** 立即执行  */
  manual?: boolean;
  /**
   * 默认参数
   * 分页参数在请放入 分页参数配置中
   */
  defaultParams?: P;
  /** 依赖刷新 */
  refreshDeps?: any[];
  /**
   * 延迟结束loading
   * 单位毫秒
   * 防止请求过快造成渲染闪烁
   */
  loadingDelay?: number;
  /**
   * 轮询间隔
   * 通过 run/runAsync 来启动轮询
   * 通过 cancel 取消轮询
   */
  pollingInterval?: number;
  /**
   * 轮询错误重试次数
   */
  pollingErrorRetryCount?: number;
  /**
   * 错误重试次数
   */
  errorRetryCount?: number;
  /**
   * 错误重试间隔
   */
  errorRetryDelay?: number;
  /**
   * 防抖等待时间
   */
  debounceWait?: number;
  /**
   * 在防抖开始前执行调用
   */
  debounceLeading?: boolean;
  /**
   * 在防抖结束后执行调用
   */
  debounceTrailing?: boolean;
  /**
   * 节流等待时间
   */
  throttleWait?: number;
  /**
   * 在节流开始前执行调用
   */
  throttleLeading?: boolean;
  /**
   * 在节流结束后执行调用
   */
  throttleTrailing?: boolean;
  /**
   * 使用分页
   */
  usePagination?: boolean;
  /**
   * 分页配置
   *
   */
  paginationConfig?: {
    /** 当前页码参数名，默认 'current' */
    currentKey?: string;
    /** 每页数量参数名，默认 'pageSize'  */
    pageSizeKey?: string;
    /** 总数字段名，默认 'total' */
    totalKey?: string;
    /** 默认当前页，默认 1 */
    defaultCurrent?: number;
    /** 默认每页数量，默认 10 */
    defaultPageSize?: number;
    /** 列表字段名，默认 'list' */
    listKey?: string;
  };
  /** 请求前 */
  onBefore?: () => Promise<void> | void;
  /** 请求成功 */
  onSuccess?: (result: R | undefined, params?: P) => void;
  /** 请求失败 */
  onError?: (error: any) => void;
  /** 请求完成 */
  onFinally?: () => void;
};

export type Service<R, P extends any[]> = (...args: P) => Promise<R>;

const useRequest = <R, P extends any[]>(
  service: Service<R, P>,
  option?: Option<R, P>,
) => {
  const loading = ref(false);

  const data = ref<R>();

  /**
   * 启用 usePagination 之后每页数据合并之后的结果
   * 为开启默认为 []
   * 只适合从第一页开始获取数据
   */
  const list = ref<R[]>([]);

  const pagination = shallowReactive({
    current: 1,
    pageSize: 10,
    total: 0,
    totalPage: 0,
    hasMore: true,
    // 分页操作方法
    setCurrent: (current: number) => {
      pagination.current = Math.max(1, current);
      refresh();
    },
    setPageSize: (pageSize: number) => {
      pagination.pageSize = pageSize;
      pagination.current = 1; // 重置到第一页
      refresh();
    },
    reset: () => {
      pagination.current = option?.paginationConfig?.defaultCurrent ?? 1;
      pagination.pageSize = option?.paginationConfig?.defaultPageSize ?? 10;
      refresh();
    },
    prev: () => {
      if (pagination.current > 1) {
        pagination.current--;
        refresh();
      }
    },
    next: () => {
      if (pagination.current < pagination.totalPage) {
        pagination.current++;
        refresh();
      }
    },
    change: (current: number, pageSize: number) => {
      pagination.current = current;
      pagination.pageSize = pageSize;
      refresh();
    },
  });

  /** 最后一次请求的参数 */
  let lastParams: P | undefined;

  let loadingTimer: any;

  let intervalTimer: any;

  let allowPolling = true;

  let pollingErrorCount = 0;

  let errorCount = 0;

  let intervalErrorRetry: ReturnType<typeof setTimeout> | undefined = undefined;

  /** 记录上次 ready 的状态 */
  let previousReady = false;

  /** 获取 ready 值 */
  const getReadyValue = (): boolean => {
    if (option?.ready === undefined) return true;
    return typeof option.ready === 'boolean'
      ? option.ready
      : option.ready.value;
  };

  /**
   *
   * @param params 请求参数
   */
  function run(...params: P) {
    if (getReadyValue()) {
      execServiceFunction(params)
        ?.catch((error) => {
          errorRetry(params);
          throw error;
        })
        ?.finally(() => {
          if (option?.pollingInterval && option.pollingInterval > 0) {
            startPolling(params);
          }
        });
    }
  }

  async function runAsync(...params: P) {
    // 只有在 ready 为 true 时才执行请求
    if (getReadyValue()) {
      try {
        const result = await execServiceFunction?.(params);

        return result;
      } catch (error) {
        errorRetry(params);
        throw error;
      } finally {
        if (option?.pollingInterval && option.pollingInterval > 0) {
          startPolling(params);
        }
      }
    }
  }

  /**
   * 刷新
   *
   */
  function refresh() {
    // 只有在 ready 为 true 时才执行请求
    if (getReadyValue()) {
      const fallbackParams: P = ((lastParams || option?.defaultParams) ??
        []) as P;

      execServiceFunction(fallbackParams);
    }
  }

  /**
   * 刷新异步
   *
   * @return {*}
   */
  function refreshAsync() {
    // 只有在 ready 为 true 时才执行请求
    if (getReadyValue()) {
      const fallbackParams: P = ((lastParams || option?.defaultParams) ??
        []) as P;

      return execServiceFunction(fallbackParams);
    }
  }

  async function execService(params: P) {
    // 只有在 ready 为 true 时才执行请求
    if (getReadyValue()) {
      try {
        loading.value = true;

        if (option?.useUniLoading) {
          uni.showLoading({
            title: '加载中...',
            mask: true,
          });
        }

        lastParams = params;

        await option?.onBefore?.();

        const result = await service(...params);

        data.value = result;

        // 如果启用了分页功能，处理分页数据
        if (option?.usePagination) {
          const config = option.paginationConfig || {};
          const currentKey = config.currentKey || 'current';
          const pageSizeKey = config.pageSizeKey || 'pageSize';
          const totalKey = config.totalKey || 'total';
          const listKey = config.listKey || 'list';

          // 检查结果是否为分页格式
          if (result && typeof result === 'object') {
            const paginationResult = result as any;
            pagination.current =
              paginationResult[currentKey] || pagination.current;
            pagination.pageSize =
              paginationResult[pageSizeKey] || pagination.pageSize;
            pagination.total = paginationResult[totalKey] || 0;
            pagination.totalPage = Math.ceil(
              pagination.total / pagination.pageSize,
            );
            pagination.hasMore = pagination.current < pagination.totalPage;

            // 获取列表数据
            const resultData =
              paginationResult[listKey] ||
              paginationResult.data ||
              paginationResult.list ||
              [];
            // 根据当前页码决定是否合并列表数据
            if (pagination.current === 1) {
              // 第一页时，替换列表
              list.value = [...resultData];
            } else {
              // 非第一页时，合并列表
              list.value = [...list.value, ...resultData];
            }
          } else {
            pagination.hasMore = false;
          }
        }

        option?.onSuccess?.(data.value, params);

        return data.value;
      } catch (error) {
        pollingErrorCount++;
        errorCount++;
        option?.onError?.(error);
        throw error;
      } finally {
        option?.onFinally?.();

        // 结束loading
        if (option?.useUniLoading) {
          // 延迟结束loading
          if (option?.loadingDelay && option.loadingDelay > 0) {
            clearTimeout(loadingTimer);

            loadingTimer = setTimeout(() => {
              loading.value = false;

              uni.hideLoading();
            }, option.loadingDelay);
          } else {
            loading.value = false;

            uni.hideLoading();
          }
        }
      }
    }
  }

  const execServiceDebounce = debounce(execService, option?.debounceWait ?? 0, {
    leading: option?.debounceLeading,
    trailing: option?.debounceTrailing,
  });

  const execServiceThrottle = throttle(execService, option?.throttleWait ?? 0, {
    leading: option?.throttleLeading,
    trailing: option?.throttleTrailing,
  });

  function execServiceFunction(params: P) {
    if (option?.usePagination) {
      const config = option.paginationConfig || {};
      const currentKey = config.currentKey || 'current';
      const pageSizeKey = config.pageSizeKey || 'pageSize';

      // 将分页参数注入到请求参数中
      const paramsWithPagination = [...params] as any[];

      // 如果参数是对象，添加分页字段
      if (
        paramsWithPagination.length > 0 &&
        typeof paramsWithPagination[0] === 'object' &&
        paramsWithPagination[0] !== null
      ) {
        paramsWithPagination[0] = {
          ...paramsWithPagination[0],
          [currentKey]: pagination.current,
          [pageSizeKey]: pagination.pageSize,
        };
      } else {
        // 如果没有参数或参数不是对象，创建一个包含分页信息的对象
        paramsWithPagination.unshift({
          [currentKey]: pagination.current,
          [pageSizeKey]: pagination.pageSize,
        });
      }

      if (option?.debounceWait) {
        return execServiceDebounce(paramsWithPagination as P);
      } else if (option?.throttleWait) {
        return execServiceThrottle(paramsWithPagination as P);
      } else {
        return execService(paramsWithPagination as P);
      }
    } else {
      if (option?.debounceWait) {
        return execServiceDebounce(params);
      } else if (option?.throttleWait) {
        return execServiceThrottle(params);
      } else {
        return execService(params);
      }
    }
  }

  /**
   * 开启轮询
   *
   * @param {P} params
   */
  function startPolling(params: P) {
    cancel();

    allowPolling = true;

    if (!getReadyValue()) return;

    // 使用递归函数实现轮询，确保请求完成后才开始计时下一次请求
    const poll = async () => {
      if (!allowPolling) return;
      // 检查 ready 状态

      try {
        await execService(params);

        // 检查错误重试次数限制
        if (
          option?.pollingErrorRetryCount &&
          pollingErrorCount >= option.pollingErrorRetryCount
        ) {
          cancel();
          return;
        }

        // 如果仍然允许轮询，则设置定时器等待下次轮询
        if (allowPolling) {
          intervalTimer = setTimeout(poll, option?.pollingInterval);
        }
      } catch (error) {
        // execService 内部已经处理了错误，这里只需要确保继续轮询或停止
        if (
          option?.pollingErrorRetryCount &&
          pollingErrorCount >= option.pollingErrorRetryCount
        ) {
          cancel();
          return;
        }

        // 如果仍然允许轮询，则设置定时器等待下次轮询
        if (allowPolling) {
          intervalTimer = setTimeout(poll, option?.pollingInterval);
        }
      }
    };

    // 先等待轮询间隔时间，然后再开始执行请求
    intervalTimer = setTimeout(() => {
      // 开始轮询
      poll();
    }, option?.pollingInterval);
  }

  /** 取消轮询 */
  function cancel() {
    allowPolling = false;
    pollingErrorCount = 0;
    errorCount = 0;
    clearInterval(intervalTimer);
    clearInterval(intervalErrorRetry);
  }

  /**
   * 错误重试
   *
   * @param {P} params
   * @return {*}
   */
  function errorRetry(params: P) {
    // 存在则不进入错误重试
    if (option?.pollingErrorRetryCount || option?.pollingInterval) return;
    // 不存在 或者 次数小于 0 不进入错误重试
    if (!option?.errorRetryCount || option.errorRetryCount <= 0) return;

    if (!getReadyValue()) return;

    const poll = async () => {
      try {
        await execService(params);
        cancel();
      } catch (error) {
        if (option.errorRetryCount && option.errorRetryCount < errorCount) {
          cancel();
          return;
        }
        intervalErrorRetry = setTimeout(poll, option?.errorRetryDelay ?? 0);
      }
    };

    intervalErrorRetry = setTimeout(poll, option?.errorRetryDelay ?? 0);
  }

  function setData(value: R) {
    data.value = value;
  }

  function setLoading(value: boolean) {
    loading.value = value;
  }

  onMounted(() => {
    // 记录初始 ready 状态
    previousReady = getReadyValue();

    // 初始化分页配置
    if (option?.usePagination) {
      const config = option.paginationConfig || {};
      pagination.current = config.defaultCurrent ?? 1;
      pagination.pageSize = config.defaultPageSize ?? 10;
    }

    if (!option?.manual && option?.ready !== false) {
      const defaultParams = (option?.defaultParams || []) as P;
      run(...defaultParams);
    }
  });

  // 监听 ready 参数变化
  watch(
    () => getReadyValue(),
    (currentReady) => {
      // 只有当 ready 从 false 变为 true 时才执行请求
      if (currentReady && !previousReady) {
        const params = (lastParams || option?.defaultParams || []) as P;
        // run(...params);
        execService(params).catch(() => {
          errorRetry(params);
        });
      } else {
        cancel();
      }
      // 更新 previousReady 状态
      previousReady = !!currentReady;
    },
  );

  watch(
    () => option?.refreshDeps,
    () => {
      refresh();
    },
    {
      deep: true,
    },
  );

  return {
    data,
    setData,
    loading,
    setLoading,
    run,
    runAsync,
    refresh,
    refreshAsync,
    cancel,
    pagination: option?.usePagination ? pagination : undefined,
    list,
  };
};

export default useRequest;
