import axios, {
  type AxiosInstance,
  type InternalAxiosRequestConfig,
  type AxiosResponse,
} from 'axios';
import type { EpPropMergeType } from 'element-plus/es/utils';
import { isNumber } from 'lodash';

export enum ResponseStatusCode {
  SUCCESS = 0,
}

interface Config<D = any> extends InternalAxiosRequestConfig<D> {
  /**
   * 隐藏错误提醒
   */
  hidden?: boolean;
}

export interface DageResponse<T = any, D = any> extends AxiosResponse<T, D> {
  code: number;
  msg: string;
  success: boolean;
}

interface Service extends AxiosInstance {
  get<T = any, R = DageResponse<T>, D = any>(url: string, config?: Config<D>): Promise<R>;
  post<T = any, R = DageResponse<T>, D = any>(
    url: string,
    data?: D,
    config?: Config<D>
  ): Promise<R>;
}

const service: Service = axios.create({
  baseURL: process.env.VUE_APP_BACKEND_URL,
  timeout: 60000,
  headers: {
    'Cache-Control': 'no-cache',
    'Content-Type': 'application/json;charset=UTF-8',
    'X-Requested-With': 'XMLHttpRequest',
  },
});

const showMessage = (
  message: string,
  type: EpPropMergeType<
    StringConstructor,
    'error' | 'success' | 'warning' | 'info',
    unknown
  > = 'error'
) => {
  ElMessage({
    showClose: true,
    type,
    duration: 4000,
    message,
  });
};

/**
 * 服务端接口empty字符串跟null返回的结果不同，过滤掉empty字符串
 * @param params
 * @param emptyString 是否过滤空字符串
 */
function filterEmptyKey(params: any, emptyString = false) {
  if (Array.isArray(params) || params == null) {
    return params;
  }

  Object.keys(params).forEach((key) => {
    if (params[key] === null || (emptyString && params[key] === '')) {
      delete params[key];
    }
  });
}

service.interceptors.request.use((config: Config) => {
  if (config.method === 'post') {
    const params = {
      ...config.data,
    };
    filterEmptyKey(params); // 过滤空字符串
    config.data = params;
  } else if (config.method === 'get') {
    config.params = {
      _t: new Date().getTime() / 1000,
      ...config.params,
    };
    filterEmptyKey(config.params, true);
  }
  return config;
});

service.interceptors.response.use(
  (res) => {
    const { data, config }: { config: Config; data: DageResponse } = res;

    // data 有可能直接返回数据
    if (isNumber(data.code) && data.code !== ResponseStatusCode.SUCCESS) {
      const msg = data.msg || '加载失败';
      const code = data.code || -1000;

      // 未手动配置 隐藏 消息提示时，公共提醒错误
      if (!config.hidden) {
        setTimeout(() => {
          showMessage(msg);
        }, 0);
      }

      return Promise.reject({
        code,
        msg,
      });
    }

    return data || {};
  },
  (error) => {
    showMessage(error.message);
  }
);

export default service as Required<Service>;
