import { message } from 'antd';
import { NoticeType } from 'antd/es/message/interface';
import axios, {
  type AxiosInstance,
  type InternalAxiosRequestConfig,
  type AxiosResponse,
} from 'axios';
import isNumber from 'lodash/isNumber';
import { getTokenInfo, removeTokenInfo } from './storage';
import { eventBus } from './eventBus';

export enum ResponseStatusCode {
  SUCCESS = 0,
  TOKEN_INVALID = 5001,
  TOKEN_INVALID2 = 5002,
}

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

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

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

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

/**
 * 服务端接口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];
    }
  });
}

const showMessage = (msg: string, type: NoticeType = 'error') => {
  message.open({
    type,
    content: msg,
    duration: 4,
  });
};

service.interceptors.request.use((config: DageConfig) => {
  const { token } = getTokenInfo();
  if (token) config.headers.token = token;

  if (config.method === 'post') {
    if (!(config.data instanceof FormData)) {
      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: DageConfig; data: DageResponse } = res;

    // data 有可能直接返回数据
    if (isNumber(data.code)) {
      if (
        [ResponseStatusCode.TOKEN_INVALID, ResponseStatusCode.TOKEN_INVALID2].includes(data.code)
      ) {
        const msg = '登录失效!';
        showMessage(msg);
        removeTokenInfo();
        eventBus.emit('Event.login.invalid', data);

        return Promise.reject({
          code: data.code,
          msg,
        });
      } else if (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);
    return new Promise((res, rej) => {
      rej(error);
    });
  },
);

export default service as Required<Service>;
