import Axios, {
  type AxiosInstance,
  type AxiosRequestConfig,
  type CustomParamsSerializer
} from "axios";
import type {
  PureHttpError,
  RequestMethods,
  PureHttpResponse,
  PureHttpRequestConfig
} from "./types.d";
import { stringify } from "qs";
import { getToken, removeToken } from "@/utils/auth";
import { ElMessage, ElMessageBox } from "element-plus";
import router from "@/router";

// API 基础 URL
const baseUrl = import.meta.env.VITE_API_URL || `${location.origin}/admin/`;

// Session 存储工具
const Session = {
  get: (key: string) => {
    const value = sessionStorage.getItem(key);
    return value ? JSON.parse(value) : null;
  }
};

// 获取 token（兼容两种存储方式）
const getAccessToken = (): string | null => {
  // 先从 auth 模块获取（主要方式）
  const authData = getToken();
  if (authData?.accessToken) {
    return authData.accessToken;
  }
  
  // 再从 Session 获取（备用方式）
  const sessionToken = Session.get('accessToken');
  return sessionToken || null;
};

// 相关配置请参考：www.axios-js.com/zh-cn/docs/#axios-request-config-1
const defaultConfig: AxiosRequestConfig = {
  // 请求超时时间
  timeout: 50000,
  baseURL: baseUrl,
  headers: {
    Accept: "application/json, text/plain, */*",
    "Content-Type": "application/json"
  },
  // 数组格式参数序列化（https://github.com/axios/axios/issues/5142）
  paramsSerializer: {
    serialize: stringify as unknown as CustomParamsSerializer
  }
};

class PureHttp {
  constructor() {
    this.httpInterceptorsRequest();
    this.httpInterceptorsResponse();
  }

  /** `token`过期后，暂存待执行的请求 */
  private static requests = [];

  /** 防止重复刷新`token` */
  private static isRefreshing = false;

  /** 防止重复跳转登录页 */
  private static isRedirecting = false;

  /** 初始化配置对象 */
  private static initConfig: PureHttpRequestConfig = {};

  /** 保存当前`Axios`实例对象 */
  private static axiosInstance: AxiosInstance = Axios.create(defaultConfig);

  /** 重连原始请求 */
  private static retryOriginalRequest(config: PureHttpRequestConfig) {
    return new Promise(resolve => {
      PureHttp.requests.push((token: string) => {
        config.headers["accessToken"] = token;
        resolve(config);
      });
    });
  }

  /** 请求拦截 */
  private httpInterceptorsRequest(): void {
    PureHttp.axiosInstance.interceptors.request.use(
      async (config: PureHttpRequestConfig): Promise<any> => {
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof config.beforeRequestCallback === "function") {
          config.beforeRequestCallback(config);
          return config;
        }
        if (PureHttp.initConfig.beforeRequestCallback) {
          PureHttp.initConfig.beforeRequestCallback(config);
          return config;
        }
        /** 请求白名单，放置一些不需要 `token` 的接口 */
        const whiteList = ["/login", "/captcha"];
        const isInWhiteList = whiteList.some(url => config.url?.includes(url));
        
        if (isInWhiteList) {
          return config;
        }
        
        // 使用 accessToken header
        const token = getAccessToken();
        if (token) {
          config.headers["accessToken"] = token;
        }
        return config;
      },
      error => {
        return Promise.reject(error);
      }
    );
  }

  /** 响应拦截 */
  private httpInterceptorsResponse(): void {
    const instance = PureHttp.axiosInstance;
    instance.interceptors.response.use(
      (response: PureHttpResponse) => {
        const $config = response.config;
        const res = response.data;
        
        // 处理业务状态码（后端返回 code 字段时才检查）
        // code: 0 或 200 表示成功，其他值表示错误
        // 如果没有 code 字段，直接返回数据
        if (res.code !== undefined && res.code !== 0 && res.code !== 200) {
          // token 过期或未登录
          if (res.code === 401) {
            if (PureHttp.isRedirecting) {
              return Promise.reject(new Error(res.msg || '未授权'));
            }
            PureHttp.isRedirecting = true;
            removeToken();
            ElMessageBox.alert('你已被登出，请重新登录', '提示', {})
              .then(() => {
                router.push('/login');
              })
              .catch(() => {
                router.push('/login');
              })
              .finally(() => {
                PureHttp.isRedirecting = false;
              });
            return Promise.reject(new Error(res.msg || '未授权'));
          }
          
          // 其他错误
          ElMessage.error(res.msg || res.message || '系统繁忙，请稍后再试！');
          return Promise.reject(new Error(res.msg || res.message || '请求失败'));
        }
        
        // 返回 res.data（与旧项目保持一致）
        // 后端返回格式: { code: 200, data: { list: [...], total: ... } }
        // 我们需要返回 data 字段的内容
        const result = res.data !== undefined ? res.data : res;
        
        // 优先判断post/get等方法是否传入回调，否则执行初始化设置等回调
        if (typeof $config.beforeResponseCallback === "function") {
          $config.beforeResponseCallback(response);
          return result;
        }
        if (PureHttp.initConfig.beforeResponseCallback) {
          PureHttp.initConfig.beforeResponseCallback(response);
          return result;
        }
        return result;
      },
      (error: PureHttpError) => {
        const $error = error;
        $error.isCancelRequest = Axios.isCancel($error);
        
        // 处理网络错误
        if (error.message?.includes('timeout')) {
          ElMessage.error('网络超时');
        } else if (error.message === 'Network Error') {
          ElMessage.error('网络连接错误');
        } else if (error.message?.includes('404')) {
          ElMessage.error('接口不存在');
        } else if (error.response?.data) {
          const data = error.response.data as any;
          ElMessage.error(data.message || error.response.statusText);
        }
        
        return Promise.reject($error);
      }
    );
  }

  /** 通用请求工具函数 */
  public request<T>(
    method: RequestMethods,
    url: string,
    param?: AxiosRequestConfig,
    axiosConfig?: PureHttpRequestConfig
  ): Promise<T> {
    const config = {
      method,
      url,
      ...param,
      ...axiosConfig
    } as PureHttpRequestConfig;

    // 单独处理自定义请求/响应回调
    return new Promise((resolve, reject) => {
      PureHttp.axiosInstance
        .request(config)
        .then((response: undefined) => {
          resolve(response);
        })
        .catch(error => {
          reject(error);
        });
    });
  }

  /** 单独抽离的`post`工具函数 */
  public post<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    return this.request<T>("post", url, params, config);
  }

  /** 单独抽离的`get`工具函数 */
  public get<T, P>(
    url: string,
    params?: AxiosRequestConfig<P>,
    config?: PureHttpRequestConfig
  ): Promise<T> {
    return this.request<T>("get", url, params, config);
  }
}

export const http = new PureHttp();
