import type {
  HttpError,
  HttpRequestAbstract,
  HttpRequestConfig,
  HttpResponse,
} from 'uview-plus/libs/luch-request/index';
import { useUserStore } from '@/store';
import { clearToken, getToken } from '@/utils/auth';
import storage from '@/utils/storage';
import { showMessage } from './status';

// 重试队列，每一项将是一个待执行的函数形式
let requestQueue: (() => void)[] = [];

// 防止重复提交
const repeatSubmit = (config: HttpRequestConfig) => {
  const requestObj = {
    url: config.url,
    data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
    time: new Date().getTime(),
  };
  const sessionObj = storage.getJSON('sessionObj');
  if (!sessionObj) {
    storage.setJSON('sessionObj', requestObj);
  }
  else {
    const s_url = sessionObj.url; // 请求地址
    const s_data = sessionObj.data; // 请求数据
    const s_time = sessionObj.time; // 请求时间
    const interval = 1000; // 间隔时间(ms)，小于此时间视为重复提交
    if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
      const message = '数据正在处理，请勿重复提交';
      console.warn(`[${s_url}]: ${message}`);
      return Promise.reject(new Error(message));
    }
    else {
      storage.setJSON('sessionObj', requestObj);
    }
  }
};

// 是否正在刷新token的标记
let isRefreshing: boolean = false;

// 跳转到登录页
const redirectToLogin = () => {
  // 清除登录状态
  clearToken();
  uni.removeStorageSync('refresh_token');
  uni.removeStorageSync('user_info');

  // 跳转到登录页
  uni.reLaunch({
    url: '/pages/common/login/index',
  });
};

// 刷新token
const refreshToken = async (http: HttpRequestAbstract, config: HttpRequestConfig) => {
  // 是否在获取token中,防止重复获取
  if (!isRefreshing) {
    // 修改登录状态为true
    isRefreshing = true;

    try {
      // 调用刷新 token 接口
      await useUserStore().refreshToken();
      // 刷新完成之后，开始执行队列请求
      requestQueue.forEach(cb => cb());
      // 重试完了清空这个队列
      requestQueue = [];
      isRefreshing = false;
      // 重新执行本次请求
      return http.request(config);
    }
    catch (error) {
      // 刷新失败，清空队列并跳转到登录页
      requestQueue = [];
      isRefreshing = false;
      redirectToLogin();
      return Promise.reject(error);
    }
  }

  return new Promise<HttpResponse<any>>((resolve) => {
    // 将resolve放进队列，用一个函数形式来保存，等登录后直接执行
    requestQueue.push(() => {
      resolve(http.request(config));
    });
  });
};

function requestInterceptors(http: HttpRequestAbstract) {
  /**
   * 请求拦截
   * @param {object} http
   */
  http.interceptors.request.use(
    (config: HttpRequestConfig) => {
      // 可使用async await 做异步操作
      // 初始化请求拦截器时，会执行此方法，此时data为undefined，赋予默认{}
      config.data = config.data || {};
      // 自定义参数
      const custom = config?.custom;

      // 是否需要设置 token
      const isToken = custom?.auth === false;
      if (getToken() && !isToken && config.header) {
        // token设置 (使用 Authorization Bearer 格式)
        config.header.Authorization = `Bearer ${getToken()}`;
      }

      // 是否显示 loading
      if (custom?.loading) {
        uni.showLoading({
          title: '加载中',
          mask: true,
        });
      }

      // 是否需要防止数据重复提交
      const isRepeatSubmit = custom?.repeatSubmit === false;
      if (!isRepeatSubmit && (config.method === 'POST' || config.method === 'UPLOAD')) {
        repeatSubmit(config);
      }
      return config;
    },
    (config: any) => // 可使用async await 做异步操作
      Promise.reject(config),
  );
}
function responseInterceptors(http: HttpRequestAbstract) {
  /**
   * 响应拦截
   * @param {object} http
   */
  http.interceptors.response.use((response: HttpResponse) => {
    /* 对响应成功做点什么 可使用async await 做异步操作 */
    const data = response.data;
    // 配置参数
    const config = response.config;
    // 自定义参数
    const custom = config?.custom;

    // 登录状态失效，尝试刷新token
    if (data.code === 401) {
      return refreshToken(http, config);
    }

    // 隐藏loading
    if (custom?.loading) {
      uni.hideLoading();
    }

    // 请求成功则返回结果 (API 文档约定 code=0 为成功)
    if (data.code === 0) {
      return response || {};
    }

    // 如果没有显式定义custom的toast参数为false的话，默认对报错进行toast弹出提示
    if (custom?.toast !== false) {
      uni.$u.toast(data.msg || '请求失败');
    }

    // 请求失败则抛出错误
    return Promise.reject(data);
  }, (response: HttpError) => {
    // 自定义参数
    const custom = response.config?.custom;

    // 隐藏loading
    if (custom?.loading !== false) {
      uni.hideLoading();
    }

    // HTTP状态码处理
    const statusCode = response.statusCode;

    // 检查是否是超时错误或网络错误
    const isTimeout = response.errMsg?.includes('timeout')
      || response.errMsg?.includes('超时')
      || response.errMsg?.includes('request:fail')
      || !statusCode; // 没有状态码通常表示网络问题或超时

    // 尝试解析响应体中的错误信息
    let errorMessage = '';
    try {
      // 如果响应体中有 data 且包含 msg 字段，优先使用后端返回的错误信息
      if (response.data && typeof response.data === 'object') {
        errorMessage = response.data.msg || '';
      }
      else if (typeof response.data === 'string') {
        // 尝试解析 JSON 字符串
        const parsedData = JSON.parse(response.data);
        errorMessage = parsedData.msg || '';
      }
    }
    catch (e) {
      // 解析失败，使用默认错误信息
    }

    // 超时错误或网络异常 - 显示服务异常提示
    if (isTimeout) {
      if (custom?.toast !== false) {
        uni.$u.toast('服务异常，请稍后重试');
      }
      return Promise.reject(response);
    }

    // 401 未授权 - 跳转登录页
    if (statusCode === 401) {
      if (custom?.toast !== false) {
        uni.$u.toast(errorMessage || '登录已过期，请重新登录');
      }
      redirectToLogin();
      return Promise.reject(response);
    }

    // 500 服务器错误 - 跳转登录页
    if (statusCode === 500) {
      if (custom?.toast !== false) {
        uni.$u.toast(errorMessage || '服务器错误，请重新登录');
      }
      redirectToLogin();
      return Promise.reject(response);
    }

    // 其他错误（包括 400 等），显示后端返回的错误信息
    if (custom?.toast !== false) {
      // 优先使用后端返回的 msg，其次使用状态码对应的默认提示
      const message = errorMessage || (statusCode ? showMessage(statusCode) : '网络连接异常,请稍后再试!');
      uni.$u.toast(message);
    }

    return Promise.reject(response);
  });
}

export { requestInterceptors, responseInterceptors };
