import * as fastify from 'fastify'
import {v4} from 'uuid'
import {Container} from 'typescript-ioc';
import {init} from "./init/initScript";
import {IPUtils} from "./utils/IPUtils";
import {registerCDPWS} from "./utils/DebugWS";
import {DebugContext} from "./utils/DebugContext";
import {TestUnitRunner} from "./test-unit/TestUnitRunner";
import {Context, EnvVariables, logger, OpResult, RedisTokenRepository} from "mslib"
import {MeHeader} from "./utils/MeHeader";
import HttpUtils from "./utils/HttpUtils";
import {NodeHttpPortUtil} from "./utils/NodeHttpPortUtil";

/**
 * 是否调试模式
 */
const isDebug: boolean = EnvVariables.getNodeEnv() === 'DEBUG';
let httpPort = NodeHttpPortUtil.getHttpPort();

const contextPath = "debugger-" + httpPort;
const testUnitRunner = new TestUnitRunner();
let dmReadyData = {};

/**
 * 开发模式下注册Debugger服务
 * @param instance
 * @param debugContext
 */
async function registerDebugger(instance: fastify.FastifyInstance, debugContext: DebugContext) {
    const inspectPort = httpPort + 9000; // CDP协议端口号
    const localIp = IPUtils.getIPAdress()

    dmReadyData =  await registerCDPWS(inspectPort, httpPort, contextPath, localIp);

    //启动调试入口
    instance.get("/startDebugger", async function (request, reply) {
        logger.info("Debugger starting.....");

        debugContext.initData = {};
        debugContext.globalZone = Zone.current.fork({name: v4(), properties: debugContext.initData || {}});

        const initData = await init();

        debugContext.initData = initData;
        debugContext.initialized = true;

        reply.code(200).send(OpResult.success("", {nodeAuth: Context.getEnv('auth.mode')}))
        logger.info("Debugger started.....");

    });


    //调试时生成Token入口
    instance.post("/addToken", async function (request, reply) {
        const body = (request.body  || {}) as any;
        if (body.userInfo) {
            const redisTokenRepository = Container.get(RedisTokenRepository)
            const addResult = await redisTokenRepository.addUserToken(body.userInfo, 60 * 1)
            if (!addResult.isSuccess()) {
                logger.info("Debugger 获取Token失败 %s", addResult.message);
            }
            reply.code(200).send(addResult)
        } else {
            reply.code(200).send(OpResult.error('用户信息不允许为空'))
        }
    });

    //调用单元测试
    instance.get("/invokeTest", async function (request, reply) {
        try {
            const query = (request.query  || {}) as any;
            const meHeader = MeHeader.parse(request.headers);
            const userInfo = MeHeader.parseUserInfo(meHeader);
            const contextProperties = {}
            contextProperties[Context.USER_INFO_PROP_NAME] = userInfo;

            let currentZone = debugContext.globalZone.fork({name: v4(), properties: contextProperties});
            currentZone.run(async () => {
                try {
                    if (query && query.servicePath) {
                        await testUnitRunner.run(query.servicePath);
                    } else {
                        await testUnitRunner.runAll();
                    }
                } catch (error) {
                    logger.error('ERROR', error)
                }
                reply.code(200).send(OpResult.success(""))
            })
        } catch (e) {
            logger.error('ERROR', e)
            reply.code(200).send(OpResult.success(""))
        }

    });
}

function getPort(): number {
    return httpPort;
}

function getContextPath(): string {
    return contextPath;
}

async function dmOnReady() {
    if(!isDebug){
        return;
    }
    const dmServerUrl = Context.getEnv('DM_SERVER_URL') + '/debuggerOnReady';
    await (HttpUtils.postJson(dmServerUrl, {}, dmReadyData));
}


export {isDebug, registerDebugger, getPort, getContextPath,dmOnReady}