/**
 * 异常模块
 * @date 2022-03
 * @author 何华东
 */

import { AxiosError } from "axios";

/**
 * 参数异常类
 * @param paramName 参数名
 */
export class ParamError extends Error {
    paramName?: string;

    constructor(message: string, paramName?: string) {
        super();

        this.name = this.constructor.name;
        this.message = message;
        this.paramName = paramName;
    }
}

/**
 * 参数无效异常类
 * @param paramName 参数名
 */
export class ParamInvalidError extends ParamError {
    constructor(paramName?: string) {
        super(`invalid ${paramName || 'param'}.`, paramName);

        this.name = this.constructor.name;
    }
}

/**
 * 参数为空异常类
 * @param paramName 参数名
 */
export class ParamEmptyError extends ParamError {
    constructor(paramName?: string) {
        super(`${paramName || 'param'} is empty.`, paramName);

        this.name = this.constructor.name;
    }
}

/**
 * 参数解密失败异常类
 * @param paramName 参数名
 */
export class ParamDecryptFailedError extends ParamError {
    constructor(paramName?: string) {
        super(`${paramName || 'param'} decrypt failed.`, paramName);

        this.name = this.constructor.name;
    }
}

/**
 * 验签失败异常类
 */
export class ValidateSignFailedError extends Error {
    constructor() {
        super('validate sign failed.');

        this.name = this.constructor.name;
    }
}

/**
 * 接口异常类
 * 
 * 主要用来替代AxiosError，因为AxiosError属性较多，而且PROD下日志组件只能输出AxiosError的Message属性
 */
export class ApiError {
    /**
     * 接口分类，例如：统一接口、非标接口、杭停接口，仅为日志记录
     */
    apiCategory: string;

    /**
     * 接口描述，例如：2.0.1获取平台配置信息，仅为日志记录
     */
    apiDesc?: string;

    /**
     * 错误信息
     */
    message?: string;

    /**
     * 请求地址
     */
    requestUrl: string;

    /**
     * 请求头
     */
    headers?: any;

    /**
     * 请求数据
     */
    data?: any;

    /**
     * axiosError.code
     * 
     * ECONNABORTED 为请求超时时
     */
    code?: string;

    /**
     * http状态码，例如：200、500、404
     */
    statusCode?: any;

    /**
     * 响应
     */
    apiResponse?: any;

    toString() {
        return `${this.apiCategory}'${this.apiDesc ? this.apiDesc : ''}'调用失败,错误信息:${this.message},请求地址:${this.requestUrl},请求头:${JSON.stringify(this.headers)},请求参数:${JSON.stringify(this.data)},HTTP状态码:${this.statusCode},返回值:${JSON.stringify(this.apiResponse)}`;
    }
}

/**
 * 从axiosError生成一个ApiError异常对象
 */
function generateApiErrorFromAxiosError(axiosError: AxiosError, apiCategory: string) {
    let apiError = new ApiError();

    apiError.apiCategory = apiCategory;
    apiError.apiDesc = axiosError.config['apiDesc'];
    apiError.message = axiosError.message;
    apiError.requestUrl = axiosError.config.url?.startsWith('http') ? axiosError.config.url : (axiosError.config.baseURL + (axiosError.config.url || ''));
    apiError.headers = axiosError.config.headers;
    apiError.data = axiosError.config.data;
    apiError.code = axiosError.code;
    apiError.statusCode = axiosError.response?.status;
    apiError.apiResponse = axiosError.response?.data;

    return apiError;
}

/**
 * 从AxiosError抛出ApiError异常
 * @param apiCategory 接口分类名
 */
export function throwApiErrorFromAxiosError(error: any, apiCategory: string) {
    if (error?.isAxiosError) throw generateApiErrorFromAxiosError(error, apiCategory);
    else throw error;
}