//接口任务 定期更新
import * as request from 'request';
import { INTERFACEREQUESTTYPEENUM } from "../../config/enum";
import { BizError } from "../../util/bizError";
import { Config } from './interfaceConfig';
const http = require('http');

//初始化接口数据
export async function initInterfaceData() {
    const InitTaskSuccess = await taskUpdate();
    // if (!InitTaskSuccess) throw new BizError("服务器启动失败: 初始化定时接口数据时出现问题 请检查目标服务器或本地请求配置");
    const InitRealTimeSuccess = await initRealTime();
    // if (!InitRealTimeSuccess) throw new BizError("服务器启动失败: 初始化实时接口数据时出现问题 请检查目标服务器或本地请求配置");
    console.log("初始化接口数据成功");
    setInterval(() => {
        taskUpdate();
    }, 10000);
}

//异常接口 不更新数据
let errorInterfaceInfo = {};

//定时接口 数据更新情况
let updateInfo = {
    "接口名称":{lastTime:0, updateUseTime:0},//使用时间是毫秒
};

//定时接口 缓存数据
let dataQueue = {};

async function taskUpdate() {
    let thisTaskInfo = [];//此次任务
    let defaultUseTime =  60000;

    let thisTime = new Date().valueOf();

    let initSuccess = true;

    for (let interfaceName in Config) {
        const LastReqError = errorInterfaceInfo[interfaceName];
        if (LastReqError) {
            console.log(`${interfaceName} 请求时出现过 ${LastReqError} 异常 保险起见此次更新不再请求`);
            continue;
        }

        const ThisConfig = Config[interfaceName];
        if (ThisConfig.type == INTERFACEREQUESTTYPEENUM.即时更新) continue;

        let lastTaskInfo = updateInfo[interfaceName];
        if ( !lastTaskInfo ) thisTaskInfo.push({name:defaultUseTime, useTime:defaultUseTime});
        else if ( lastTaskInfo && (thisTime - lastTaskInfo) > ThisConfig.time ) {
            thisTaskInfo.push({name:defaultUseTime, useTime:lastTaskInfo.updateUseTime});
        }
        defaultUseTime += 1;
    }
    thisTaskInfo.sort((a, b) => {return a.useTime - b.useTime});//耗时短的优先

    for (let i = 0; i < thisTaskInfo.length; i++) { //更新数据
        let {name} = thisTaskInfo[i];
        const ThisConfig = Config[name];
        const StartTime = new Date().valueOf();
        
        let reqRes;
        switch(ThisConfig.reqType) {
            case "get": reqRes = await get(ThisConfig.url, ThisConfig.body, ThisConfig.header); break;
            case "post": reqRes = await post(ThisConfig.url, ThisConfig.body, ThisConfig.header); break;
            case "postForm": reqRes = await postForm(ThisConfig.url, ThisConfig.body); break;
        }
        const UseTime = new Date().valueOf() - StartTime;
        if (reqRes.success) {
            if (!updateInfo[name]) updateInfo[name] = {lastTime:thisTime, updateUseTime:UseTime};
            else {
                updateInfo[name].lastTime = thisTime;
                updateInfo[name].updateUseTime = UseTime;
            }
            if (dataQueue[name]) delete dataQueue[name];
            dataQueue[name] = JSON.stringify(reqRes.body);//放入缓存
        } else {
            let errorMsg = reqRes.message;
            if (reqRes.message && reqRes.message.code == "ESOCKETTIMEDOUT") errorMsg = "超时";
            console.log(`接口 ${name} 请求失败 失败原因${errorMsg}`);
            if (["404", "503"].indexOf(errorMsg) > -1) { //下次不再请求
                errorInterfaceInfo[name] = errorMsg;
            }
            initSuccess = false;
        }
    }
    return initSuccess;
}


//即时数据缓存 当请求失败时会用到这里的数据
let realTimeDataQueue = {};

//即时数据初始化
async function initRealTime() {
    let initSuccess = true;
    for (let interfaceName in Config) {
        const ThisConfig = Config[interfaceName];
        if (ThisConfig.type == INTERFACEREQUESTTYPEENUM.定时更新) continue;
        let reqRes;
        switch(ThisConfig.reqType) {
            case "get": reqRes = await get(ThisConfig.url, ThisConfig.body, ThisConfig.header); break;
            case "post": reqRes = await post(ThisConfig.url, ThisConfig.body, ThisConfig.header); break;
            case "postForm": reqRes = await postForm(ThisConfig.url, ThisConfig.body); break;
        }
        if (!reqRes.success) {
            console.log(`${interfaceName} 接口请求失败 请求地址为 ${ThisConfig.url} 失败原因 ${reqRes.message}`);
            initSuccess = false;
        }
        realTimeDataQueue[interfaceName] = reqRes.data;
    }
    return initSuccess;
}

export async function getInterfaceByInterfaceName(name, body?, header?) {
    const ThisConfig = Config[name];
    let data:any;
    if (ThisConfig.type == INTERFACEREQUESTTYPEENUM.即时更新) {
        let reqRes;
        let reqBody = Object.assign( ThisConfig.body|| {},  body || {});
        let reqHeader = Object.assign( ThisConfig.header|| {},  header || {});
        switch(ThisConfig.reqType) {
            case "get": reqRes = await get(ThisConfig.url, reqBody, reqHeader); break;
            case "post": reqRes = await post(ThisConfig.url, reqBody, reqHeader); break;
            case "getParmiss": reqRes = await getParmiss(ThisConfig.url, reqBody, reqHeader); break;
            case "postParmiss": reqRes = await postParmiss(ThisConfig.url, reqBody, reqHeader); break;
            case "postForm": reqRes = await postForm(ThisConfig.url, reqBody ); break;
            case "postPHP": reqRes = await postPHP(ThisConfig.url, reqBody, reqHeader); break;
        }
        if (reqRes.success) {
            data = reqRes.data;
        } else {
           data = realTimeDataQueue[name];
        }
        
    } else data = dataQueue[name];
    return data;
}


function get(url:string, query?, headers?, timeOut?) {
    timeOut = timeOut || 5000;
    if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
    return new Promise((resolve, reject)=>{
        let paramater:any = { url, json:true, timeout:timeOut };
        if (query) paramater.qs = query;
        if (headers) paramater.headers = headers;
        request.get(paramater, function (err, res, data) {
           const success = !err && res && res.statusCode == 200;
           let message = err || res.statusCode || "";
           resolve({success, message, data});
        })
    })
}


function post(url, body, headers) {
    if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
    let header = {"content-type": "application/json"};  
    return new Promise((resolve, reject)=>{
        request({
            url: url,
            method: "POST",
            json: true,
            headers: Object.assign(header, headers),
            body: body
        }, function(error, response, data) {
            if (!error && response.statusCode == 0) {
                resolve(data);
            }
            else {
                reject(error || `${url} => ${JSON.stringify(data)}`)
            }
        });
    })
}


function postForm(url, body) {
    if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
    return new Promise((resolve, reject)=>{
        request({
            url: url,
            method: "POST",
            json: true,
            form:body
        }, function(err, res, data) {
            const success = !err && res && res.statusCode == 200;
            let message = err || res.statusCode || "";
            resolve({success, message, data});
        });
    })
}



function postParmiss(url, reqBody, headers) {
    if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
    return new Promise((resolve, reject)=>{
        request({
            url: url,
            method: "POST",
            json: true,
            form: reqBody
        }, function(error, response, body) {
            resolve(body);
        });
    })
}


function getParmiss(url, query?, headers?) {
    return new Promise((resolve, reject)=>{
        let paramater:any = { url, json:true };
        if (query) paramater.qs = query;
        if (headers) paramater.headers = headers;
        request.get(paramater, function (err, r, body) {
            if (err) return resolve(err);
            if (r && r.statusCode != 200) return resolve( { error: 'httpError:'+r.statusCode })
            resolve(body);
        });
    })
}



function postPHP(url, body, headers) {
    if (!url || (url.search(/http:/) && url.search(/https:/)) ) throw new BizError(!url ? "请求地址为空" : "请求地址错误");
    let header = {"content-type": "application/json"};  
    return new Promise((resolve, reject)=>{
        request({
            url: url,
            method: "POST",
            json: true,
            headers: Object.assign(header, headers),
            body: body
        }, function(error, response, body) {
            resolve(body);
        });
    })
}
