import axios, { AxiosRequestConfig } from 'axios';
import { TOKEN } from '~/store/login';
import router from '~/router';
import useLoginStore from "~/store/login";
import { ElMessage, ElMessageBox } from 'element-plus';
import type { Action } from 'element-plus';

// 是否显示过提示登录框 防止重复提示
let isShowLoginBox = false;
// 是否线上未授权提示框 防止重复提示
let isShowAuthBox = false;
/**
 * 控制台输出
 */
const log = (type: string, ...msg: any): void => {
  // console.log(`[ axios ] ${type} => `, ...msg);
};
/**
 * 获取token
 */
const getToken = (): string => {
  const login = useLoginStore()
  return login.token
};
/**
 * 显示提示登录框
 */
const showLoginBox = (msg: string): void => {
  if (router.currentRoute.value.path != '/login' && !isShowLoginBox) {
    isShowLoginBox = true;
    // 到登录页
    ElMessageBox.alert(msg, '提示', {
      type: 'warning',
      showClose: false,
      confirmButtonText: 'OK'
    }).then(() => {
      isShowLoginBox = false;
      const login = useLoginStore()
      login.logout()
    });
  }
};
/**
 * 显示授权框
 */
const showAuthBox = (msg: string): void => {
  if (import.meta.env.DEV) {
    if (!isShowAuthBox) {
      isShowAuthBox = true;
      ElMessageBox.confirm(msg, '提示', {
        type: 'warning',
        confirmButtonText: '去授权',
        cancelButtonText: '刷新',
        distinguishCancelAndClose: true,
        callback(action: Action) {
          switch (action) {
            case 'confirm':
              isShowAuthBox = false;
              const route = router.resolve({
                path: '/menu/api'
              });
              window.open(route.href, '_blank');
              break;
            case 'cancel':
              window.location.reload()
              break;

            default:
              break;
          }
        }
      })
    }
  } else {
    router.push('/exception/403');
  }
}
/**
 * 常用的contentTyp类型
 */
export const ContentType = {
  // json
  JSON: 'application/json;charset=UTF-8',
  // text
  TEXT: 'text/plain;charset=UTF-8',
  // form-data 一般配合qs
  FORM_URLENCODED: 'application/x-www-form-urlencoded;charset=UTF-8',
  // form-data  上传
  FORM_DATA: 'multipart/form-data;charset=UTF-8'
};

/**
 * @description: 请求结果集
 */
export const Result = {
  SUCCESS: 0,
  ERROR: -1,
  // 登录超时
  LOGIN_TIMEOUT: 40026,
  // 未授权接口
  NOT_AUTH_API: 40050,
  TYPE: 'success'
};

/**
 * @description: 请求方法
 */
export const Request = {
  GET: 'GET',
  POST: 'POST',
  PATCH: 'PATCH',
  PUT: 'PUT',
  DELETE: 'DELETE'
};

type downloadFileOptions = {
  method?: 'post' | 'get'
  withToken?: boolean
  target?: string
}
/**
 * 下载文件
 * @param {String} path 文件路径
 * @param {Object} data 数据 key: value
 * @param {Object} options 配置项
 * @param {String} options.method 请求类型 post | get
 * @param {Boolean} options.withToken 是否携带token
 * @param {String} options.target 下载方式
 */
export function downloadFile(path: string, data: Object = {}, options: downloadFileOptions = {}): void {
  const { method = 'post', withToken = true, target = '_blank' } = options;
  const form = document.createElement('form');
  form.action = path;
  form.method = method;
  form.target = target;
  try {
    if (withToken) {
      data[TOKEN] = getToken();
    }
    for (const key in data) {
      if (Object.hasOwnProperty.call(data, key)) {
        const input = document.createElement('input');
        input.name = key;
        input.value = data[key];
        form.appendChild(input);
      }
    }
    document.body.appendChild(form);
    form.submit();
  } catch (error) {
    console.error('[ downloadFile ]', error);
  } finally {
    document.body.removeChild(form);
  }
}

type uploadFile = {
  url: string
  name?: string
  multiple?: boolean
  withToken?: boolean
  axiosConfig?: AxiosRequestConfig
}
export function uploadFile(options: uploadFile) {
  return new Promise((resolve) => {
    const { withToken = true, axiosConfig = {} } = options
    const $input = document.createElement('input')
    $input.type = 'file'
    $input.multiple = !!options.multiple
    try {
      document.body.appendChild($input)
      $input.click()
      const name = [
        options.name ? options.name : 'file',
        $input.multiple ? '[]' : ''
      ].join('')
      $input.onchange = async () => {
        const files = $input.files
        if (!files.length) {
          throw new Error("未选择文件");
        }
        const form = new FormData
        if (withToken) {
          form.set(TOKEN, getToken());
        }
        Array.from(files).forEach(file => {
          form.append(name, file)
        })
        resolve(await api.post(options.url, form, axiosConfig))
      }
    } catch (error) {
      console.error('[ uploadFile ]', error)
    } finally {
      document.body.removeChild($input)
    }
  })
}

export type BaseRespone = {
  code: number
  msg: string
}

/**
 * 判断返回状态码是否成功
 * @param {BaseRespone} res 请求函数
 * @param {String|Number} code 状态码
 */
export function isRequestSuccess(res: BaseRespone, code: number | string = Result.SUCCESS): boolean {
  return res.code == code
}

/**
 * 创建Api url
 * @param {String} url 
 */
export function createApiUrl(url: string): string {
  if (import.meta.env?.VITE_API_GATEWAY) {
    return `${import.meta.env.VITE_API_GATEWAY}/${url}`;
  }
  return `/api/${url}`;
}

/**
 * axios 实例
 */
export const api = axios.create({
  baseURL: createApiUrl(''),
  //   timeout: 1000,
  headers: {
    'X-Requested-With': 'XMLHttpRequest'
  }
});

// 添加请求拦截器
api.interceptors.request.use(
  config => {
    const token = getToken();
    if (token && !config.headers?.token) {
      config.headers.token = token;
    }

    log('request', config.method, config.url, {
      ...config.data,
      ...config.params
    });
    // 在发送请求之前做些什么
    return config;
  },
  error => {
    // 对请求错误做些什么
    return Promise.reject(error);
  }
);

// 添加响应拦截器
api.interceptors.response.use(
  response => {
    const { config, data } = response;
    log('response', config.method, config.url, response);
    const {
      // 是否提示消息
      isShowMessage = true,
      // 是否提示异常消息
      isShowErrorMessage,
      // 是否提示成功消息
      isShowSuccessMessage,
      // 成功提示信息
      successMessageText,
      // 异常提示消息
      errorMessageText,
      // 异常提示模式
      errorMessageMode,
      // 是否进行数据判断
      isTransformResponse,
      // 是否获取原生响应
      isReturnNativeResponse,
      // 忽略登录
      ignoreLogin = false,
      // 返回请求成功状态码
      returnRequestSuccess = false
    } = config;
    // 是否返回原生响应头 比如：需要获取响应头时使用该属性
    if (isReturnNativeResponse) {
      return response;
    }
    // 不进行任何处理，直接返回
    // 用于页面代码可能需要直接获取code，data，message这些信息时开启
    if (!isTransformResponse) {
      return data;
    }
    const token = getToken();
    // 忽略登录
    if (!ignoreLogin && !token) {
      showLoginBox('请登录');
      throw new Error('请登录');
    }
    if (!data) {
      // return '[HTTP] Request has no return value';
      throw new Error('请求出错，请稍候重试');
    }
    const { code, msg, message } = data;
    // 请求成功
    const isSuccess = code === Result.SUCCESS;
    // 是否显示提示信息
    if (isShowMessage) {
      if (isSuccess && (successMessageText || isShowSuccessMessage)) {
        // 是否显示自定义信息提示
        ElMessage.success(successMessageText || msg || message || '操作成功！');
      } else if (!isSuccess && (errorMessageText || isShowErrorMessage)) {
        // 是否显示自定义信息提示
        ElMessage.error(msg || message || errorMessageText || '操作失败！');
      } else if (!isSuccess && errorMessageMode === 'modal') {
        // errorMessageMode=‘custom-modal’的时候会显示modal错误弹窗，而不是消息提示，用于一些比较重要的错误
        // $dialog.info({
        //   title: "提示",
        //   content: msg,
        //   positiveText: "确定",
        //   onPositiveClick: () => {},
        // });
      }
    }
    // 返回请求成功状态码
    if (returnRequestSuccess !== false) {
      return isRequestSuccess(
        data,
        returnRequestSuccess === true ? Result.SUCCESS : returnRequestSuccess
      );
    }
    // 接口请求成功，直接返回结果
    if (isSuccess) {
      return data;
    }
    // 接口请求错误，统一提示错误信息 这里逻辑可以根据项目进行修改
    let errorMsg = msg;
    switch (code) {
      // 请求失败
      case Result.ERROR:
        ElMessage.error(errorMsg);
        break;
      // 未授权接口
      case Result.NOT_AUTH_API:
        // 已登录
        if (token) {
          showAuthBox(errorMsg)
        }
        break;
      // 登录超时
      case Result.LOGIN_TIMEOUT:
        errorMsg = '登录超时，请重新登录!';
        showLoginBox(errorMsg);
        break;
    }
    throw new Error(errorMsg);

    // 2xx 范围内的状态码都会触发该函数。
    // 对响应数据做点什么
    return response;
  },
  error => {
    // 超出 2xx 范围的状态码都会触发该函数。
    // 对响应错误做点什么
    return Promise.reject(error);
  }
);
