/*
 * @Description: axios统一调用工具类
 * @Author: liusheng
 * @Date: 2021-01-17 22:43:52
 */
import axios from 'axios'
import Constant from './CommonConst.js'
import DateUtil from './DateUtil.js'
import SysMaintain from '../utilcomp/sysmaintain/SysMaintain.vue'

// Vue实例，由init方法初始化
let vueInstance = null;

// IMS公告获取地址，由init方法初始化
let publicNoticeRequestUrl = null;

/*
 * Restful请求返回2012(未登录)时的回调函数，由init方法初始化
 * @param {object} vue Vue实例
 * @param {string} url 接口的请求地址
 * @return {boolean} true/false-通知AppAxios是否显示toast
 */
let notLoginCallbackFunc = null;

/*
 * Restful请求返回502时所调用的函数
 * @param {object} vue Vue实例
 * @return {boolean} true-已进行错误处理，false-未进行错误处理
 */
let http502CallbackFunc = async function trySysMaintainNotice(vue) {
    if (publicNoticeRequestUrl == null) return false;

    try {
        let res = await fetch(publicNoticeRequestUrl);
        let result = await res.json();

        if (result.code != Constant.RESTFUL_SUCC || result.data == null) return false;

        let {content, timeRange} = {...result.data};
        vue.$router.push({ path: '/sysmaintain', query: {content: content, timeRange: timeRange} });
        return true;
    } catch (err) {
        console.log(err);
        return false;
    }
};

/**
 * appAxios初始化函数。各项目在调用appAxios前，应首先调用本函数对其进行初始化
 * @Author: liusheng, fengal
 * @Date: 2022-04-03 08:43:12
 * @param {object} vue Vue实例
 * @param {function} notLoginCallback Restful请求返回2012(未登录)时的回调函数
 * @param {string} router 路由实例
 * @param {string} publicNoticeUrl IMS公告获取地址
 */
function initAppAxios(vue, notLoginCallback, router, publicNoticeUrl) {
    vueInstance = vue;
    notLoginCallbackFunc = notLoginCallback;

    // 添加SysMaintain路由
    let newRoutes = [{
        path: '/sysmaintain',
        name: 'sysmaintain',
        component: SysMaintain,
    }]

    if (router != null && publicNoticeUrl != null) {
        router.options.routes.push(...newRoutes);
        router.addRoutes(newRoutes);
        publicNoticeRequestUrl = publicNoticeUrl;
    }

}

/**
 * 通用的restful接口请求方法，所有接口请求均须通过调用此方法来实现
 * @Author: liusheng
 * @Date: 2021-02-06 08:43:12
 * @param {string} method 请求方法 GET|POST|PUT|DELETE<br/>
 *        注：对于POST|PUT|DELETE请求自动遮罩， GET请求带~后缀表示显示遮罩，如GET~
 * @param {string} url 请求的url地址
 * @param {object} param 请求参数
 * @param {string} contentType MIME类型，通过Constant常量指定
 * @param {bool} showSuccMsg 是否显示调用成功信息，默认为false
 * @param {bool} showFailMsg 是否显示调用失败信息，默认为true
 *
 * @return {resolve} 请求成功的数据(code=2000)，或null(code=2001)错误
 * @return {reject} 2009（用户不存在时，code=2009）
 * @return {reject} 2010（用户被禁用时，code=2010）
 * @return {redirect} 用户未登录(code=2012)，直接重定向到Login页面
 * @return {reject} 错误信息（网络请求错误时）
 */
let appAxios = function restfulRequest(method, url, param, contentType,
        showSuccMsg = false, showFailMsg = true) {
    console.log("Calling interface:", method, url);
    if (!contentType) {
        contentType = Constant.CNTYPE_JSON;
    }
    method = method.toUpperCase();
    let showLoading = method.endsWith('~') || method != 'GET';
    if (method.endsWith('~')) {
        method = method.slice(0, method.length - 1);
    }

    let loading = !showLoading ? null : vueInstance.$loading({
        lock: true,
        text: '正在请求服务器，请稍候',
        spinner: 'el-icon-loading',
        background: 'rgba(0, 0, 0, 0.5)'
    });
    return callAxios(method, url, param, contentType, loading, showSuccMsg, showFailMsg);
}

function callAxios(method, url, param, contentType, loading, showSuccMsg, showFailMsg) {
    let config = makeAxiosRequestConfig(method, url, param, contentType);
    return new Promise((resolve, reject) => {
        axios.request(config).then(response => {
            if (loading) loading.close();
            console.log(response.data.time, method, url, response.data);

            let result = processResult(url, response.data, showSuccMsg, showFailMsg);
            switch (result.code) {
                case Constant.RESTFUL_LOGIN_USER_NOT_EXIST:
                    reject(Constant.RESTFUL_LOGIN_USER_NOT_EXIST);
                    return;
                case Constant.RESTFUL_FORBID_LOGIN:
                    reject(Constant.RESTFUL_FORBID_LOGIN);
                    return;
                default:
                    resolve((result.code == Constant.RESTFUL_SUCC) ? result : null);
                    return;
            }
        }).catch(err => {
            if (loading) loading.close();
            processError(method, url, err);
            reject(err);
        });
    });
}

function makeAxiosRequestConfig(method, url, param, contentType) {
    let config = { url: url, method: method, timeout: 120000 };
    switch (method) {
        case 'GET':
            config.params = param;
            break;
        case 'POST':
        case 'PUT':
        case 'DELETE':
            config.headers = { 'content-type': contentType };
            config.data = param;
            break;
    }
    return config;
}

/*
 * @Description: 处理接口请求返回结果
 * @Author: liusheng
 * @Date: 2021-02-06 09:02:14
 * @param {string} url 接口的请求地址
 * @param {object} result 接口的直接返回结果(ResponseResult)
 * @param {bool} showSuccMsg 是否显示成功信息
 * @param {bool} showFailMsg 是否显示失败信息
 * @return {*} 除result.code==RESTFUL_NOT_LOGIN跳转首页外，原样返回result
 */
function processResult(url, result, showSuccMsg, showFailMsg) {
    switch (result.code) {
        case Constant.RESTFUL_SUCC:
            if (showSuccMsg) vueInstance.$message({ message: result.data, type: 'success' });
            break;
        case Constant.RESTFUL_NOT_LOGIN:
            let showToast = false;
            if (notLoginCallbackFunc != null) {
                showToast = notLoginCallbackFunc(vueInstance, url);
            } else {
                vueInstance.$router.push('login');
            }
            // 如果url中包含'common',表示是pageframe中的请求，不显示toast
            if ((url.split("/").indexOf("common") == -1 || showToast) && showFailMsg) {
                vueInstance.$message({ message: result.msg, type: 'warning' });
            }
            break;
        case Constant.RESTFUL_FAIL:
        case Constant.RESTFUL_LOGIN_USER_NOT_EXIST:
        case Constant.RESTFUL_FORBID_LOGIN:
            if (showFailMsg) vueInstance.$message.error(result.msg);
            break;
        default:
            if (showFailMsg) vueInstance.$message.error("未知结果Code：" + result.code);
            break;
    }

    return result;
}

/*
 * @Description: 处理接口请求时发生的错误
 * @Author: liusheng, fengal
 * @Date: 2021-02-06 09:06:38
 * @param {*} method 请求方法
 * @param {*} url 请求地址
 * @param {*} err 错误信息
 * @return {*}
 */
async function processError(method, url, err) {
    let processed = false;

    console.log('调用processError', method, url, err);

    if (err.response.status == 502) {
        processed = (await http502CallbackFunc(vueInstance));
    }
    if (processed) return;

    let time = DateUtil.dateTimeFormat(new Date());
    console.error(time, method, url, err);
    vueInstance.$message.error("服务器错误:" + err);
}

export { initAppAxios, appAxios }
