import { HeaderType } from "../constants/enum/header-type.enum";
import { tokenStore } from "../stores/token.store";
import { MethodType } from "../constants/enum/method-type.enum";
import { StatusCode } from "../constants/enum/status-code.enum";
import { RestfulResponse } from "../model/domain/RestfulResponse";
import { Code } from "../constants/enum/code.enum";
import { coreEventService } from "../services/core-event.service";
import { AuthEventType } from "../constants/enum/auth-event-type.enum";
import axios, { Axios, AxiosRequestConfig } from "axios";
import { oauthService, OauthService } from "./oauth.service";
import { Modal } from "ant-design-vue";

interface Query {
  [key: string]: any;
}
/**
 * @description: REST请求服务
 * @author ChenRui
 * @date 2020/7/29 18:45
 */
class ApiService {
  logoutNoticeSign = false; // 登出通知标志
  axiosInner: Axios;

  constructor() {
    const requestConfig: any = this.createBasicHeaders();
    this.axiosInner = axios.create(requestConfig);
    this.axiosInner.interceptors.request.use(
      (config: AxiosRequestConfig | any) => {
        // Do something before request is sent
        if (this.verificationToken(config)) {
          return config;
        } else {
          if (!this.logoutNoticeSign) {
            this.logoutNoticeSign = true;
            return oauthService.refreshToken().then((response: RestfulResponse) => {
              this.logoutNoticeSign = false;
              if (response && response.code === Code.SUCCESS.code) {
                config.headers = config.headers ? config.headers : {};
                config.headers.Authorization = "bearer " + tokenStore.token?.accessToken;
                config.headers["user-identity"] = tokenStore.token?.jti as string;
                return Promise.resolve(config);
              } else {
                if (oauthService.authConfig.enableNoticeMode) {
                  coreEventService.emit(OauthService.AUTH_EVENT_NAME, { type: AuthEventType.LOGOUT.code });
                } else {
                  Modal.warning({
                    title: "会话已失效",
                    content: "会话已失效，请重新登录",
                    okText: "确定",
                    onOk: () => {
                      return oauthService.logOut();
                    },
                  });
                }
                return Promise.reject("会话已失效");
              }
            });
          }
        }
      },
      (error) => {
        return Promise.reject("网络异常，请稍后再试");
      }
    );
  }

  /**
   * @description:  创建基础消息头
   * @author ChenRui
   * @date 2020/8/28 15:18
   */
  createBasicHeaders(): any {
    return {
      headers: {
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    };
  }

  /**
   * @description: 创建认证消息头
   * @author ChenRui
   * @date 2020/8/28 15:18
   */
  createAuthHeaders(): any {
    return {
      headers: {
        Authorization: "bearer " + tokenStore.token?.accessToken,
        "user-identity": tokenStore.token?.jti,
        "Content-Type": "application/json",
        Accept: "application/json",
      },
    };
  }

  /**
   * @description: 创建上传认证消息头
   * @author ChenRui
   * @date 2021/4/6 11:17
   */
  createFileUploadAuthorizationHeader() {
    return {
      headers: {
        Accept: "application/json",
        Authorization: "bearer " + tokenStore.token?.accessToken,
        "user-identity": tokenStore.token?.jti,
      },
    };
  }

  /**
   * @description: 创建认证下载消息头
   * @author ChenRui
   * @date 2020/8/28 15:18
   */
  createFileDownloadAuthorizationHeader() {
    return {
      headers: {
        "Content-Type": "application/json",
        Authorization: "bearer " + tokenStore.token?.accessToken,
        "user-identity": tokenStore.token?.jti,
      },
      responseType: "blob",
    };
  }

  get(path: string, query: Query | undefined, requestConfig: AxiosRequestConfig): any {
    path = query != null ? this.urlQueryConvert(path, query) : path;
    return this.axiosInner.get(`${path}`, requestConfig).then(this.createBusCodeHander()).catch(this.createErrorHander());
  }

  post(path: string, params: any, query: Query | undefined, requestConfig: AxiosRequestConfig): any {
    path = query != null ? this.urlQueryConvert(path, query) : path;
    return this.axiosInner.post(`${path}`, params, requestConfig).then(this.createBusCodeHander()).catch(this.createErrorHander());
  }

  put(path: string, params: any, query: Query | undefined, requestConfig: AxiosRequestConfig): any {
    path = query != null ? this.urlQueryConvert(path, query) : path;
    return this.axiosInner.put(`${path}`, params, requestConfig).then(this.createBusCodeHander()).catch(this.createErrorHander());
  }

  delete(path: string, query: Query | undefined, requestConfig: AxiosRequestConfig): any {
    path = query != null ? this.urlQueryConvert(path, query) : path;
    return this.axiosInner.delete(path, requestConfig).then(this.createBusCodeHander()).catch(this.createErrorHander());
  }

  /**
   * @description: 通用请求函数
   * @author ChenRui
   * @date 2020/8/28 15:19
   * @param api               调用接口的对象
   * @param query             问号？后参数
   * @param params            post、put、delete参数 非必须
   * @param requestConfig     请求配置，如果上传文件、form提交等配置 非必须
   */
  general(api: any, query?: Query | undefined, params?: any | undefined, requestConfig?: AxiosRequestConfig | any): any {
    if (!!api.url && !!api.method) {
      if (requestConfig == null) {
        switch (api.header) {
          case HeaderType.BASE.code:
            requestConfig = this.createBasicHeaders();
            break;
          case HeaderType.AUTH.code:
            requestConfig = this.createAuthHeaders();
            break;
          case HeaderType.UPLOAD_AUTH.code:
            requestConfig = this.createFileUploadAuthorizationHeader();
            break;
          case HeaderType.DOWNLOAD_AUTH.code:
            requestConfig = this.createFileDownloadAuthorizationHeader();
            break;
        }
      } else {
        let requestConfigBase: any = {};
        switch (api.header) {
          case HeaderType.BASE.code:
            requestConfigBase = this.createBasicHeaders();
            break;
          case HeaderType.AUTH.code:
            requestConfigBase = this.createAuthHeaders();
            break;
          case HeaderType.UPLOAD_AUTH.code:
            requestConfigBase = this.createFileUploadAuthorizationHeader();
            break;
          case HeaderType.DOWNLOAD_AUTH.code:
            requestConfigBase = this.createFileDownloadAuthorizationHeader();
            break;
        }
        Object.keys(requestConfig).forEach((value, index, array) => {
          requestConfigBase[value] = requestConfig[value];
        });
        requestConfig = requestConfigBase;
      }
      switch (api.method) {
        case MethodType.GET.code:
          return this.get(api.url, query, requestConfig);
          break;
        case MethodType.PUT.code:
          return this.put(api.url, params, query, requestConfig);
          break;
        case MethodType.POST.code:
          return this.post(api.url, params, query, requestConfig);
          break;
        case MethodType.DELETE.code:
          return this.delete(api.url, query, requestConfig);
          break;
      }
    }
  }

  /**
   * @description: 错误码处理器
   * @author ChenRui
   * @date 2020/8/28 15:19
   */
  createBusCodeHander() {
    return function (response: any) {
      if (response.status === 200) {
        if (response.data && response.data.meta && String(response.data.meta.statusCode) === StatusCode.USER_CACHE_DOES_NOT_EXIST.code) {
          oauthService.refreshToken();
        }
        return response.data;
      }

      return response;
    };
  }

  /**
   * @description: 异常处理器
   * @author ChenRui
   * @date 2020/8/28 15:19
   */
  createErrorHander() {
    return function (error: any) {
      let msg = "未知异常，稍后请重试或联系管理员";
      if (error.request) {
        msg = error.request?.data?.msg || "网络连接异常，稍后请重试或联系管理员";
      } else if (error.response) {
        msg = error.response?.data?.msg || "服务器异常，稍后请重试或联系管理员";
      } else if (error && typeof error === "string") {
        msg = error;
      } else if (error && error.code && error.msg) {
        msg = error.msg;
      }
      return RestfulResponse.failure(msg);
    };
  }

  /**
   * @description: 校验令牌
   * @author ChenRui
   * @date 2021/8/11 15:02
   */
  verificationToken(config: AxiosRequestConfig) {
    if (config.headers && config.headers.Authorization && (config.headers.Authorization as string).indexOf(OauthService.BASE_TOKEN_TYPE) != 0) {
      if (tokenStore.token) {
        return oauthService.isTokenExpiration;
      } else {
        return false;
      }
    }
    return true;
  }

  /**
   * @description: 日期格式化
   * @author ChenRui
   * @date 2020/8/28 15:20
   */
  formatDate(date: any) {
    date = new Date(date);
    const YY = date.getFullYear() + "-";
    const MM = (date.getMonth() + 1 < 10 ? "0" + (date.getMonth() + 1) : date.getMonth() + 1) + "-";
    const DD = date.getDate() < 10 ? "0" + date.getDate() : date.getDate();
    const hh = (date.getHours() < 10 ? "0" + date.getHours() : date.getHours()) + ":";
    const mm = (date.getMinutes() < 10 ? "0" + date.getMinutes() : date.getMinutes()) + ":";
    const ss = date.getSeconds() < 10 ? "0" + date.getSeconds() : date.getSeconds();
    return YY + MM + DD + " " + hh + mm + ss;
  }

  /**
   * @description: json格式转表单格式
   * @author ChenRui
   * @date 2020/8/28 15:20
   */
  jsonToFormData(params: any) {
    if (params != null) {
      const formData = new FormData();
      Object.keys(params).forEach((key) => {
        formData.append(key, params[key]);
      });
      return formData;
    }
  }

  /**
   * @description: url请求参数组装
   * @author ChenRui
   * @date 2020/8/28 15:21
   */
  urlQueryConvert(url: string, query: Query) {
    let connectiveSymbol = "";
    if (url.indexOf("?") !== -1) {
      connectiveSymbol = "&";
    } else {
      connectiveSymbol = "?";
    }
    if (query) {
      Object.keys(query).forEach((key, idx) => {
        const val = query[key];
        if (idx === 0) {
          if (val != null && val !== "null" && val !== "undefined") {
            url += connectiveSymbol + key + "=" + val;
          } else {
            url += connectiveSymbol + key + "=";
          }
        } else {
          if (val != null && val !== "null" && val !== "undefined") {
            url += "&" + key + "=" + val;
          } else {
            url += "&" + key + "=";
          }
        }
      });
    }
    return url;
  }
}
const apiService = new ApiService();
export { apiService };
