require('xprofiler').start({
    log_dir: '/zyz_logs/xprofiler',
});
import { COM_TEAM_STATUS, STATUS } from './app/consts';
import {
    createTcpAcceptor,
    createTcpMailBox,
    FrontendOrBackendSession,
    HandlerCallback,
    pinus,
    RESERVED,
    RouteRecord
} from 'pinus';
import * as mongoose from 'mongoose';
import * as redisService from './app/services/redisService';
import './app/servers/user.rpc.define'
import * as  routeUtil from './app/util/routeUtil';
import { preload } from './preload';
import { globalFilter } from'./app/servers/connector/filter/global';
import { guildAuthFilter } from'./app/servers/guild/filter/guildAuthFilter';
import { tokenFilter } from'./app/servers/gm/filter/tokenFilter';
import { connectRedis } from './app/pubUtils/redis';
import * as timeTaskService from './app/services/timeTaskService';
import * as redlockCacheService from './app/services/redlockCacheService';
import * as redLockService from './app/services/redLockService';
// TODO 需要整理。
import _pinus = require('pinus');
import { updateTeamStatus } from './app/services/comBattleService';
import { resResult, genCode } from './app/pubUtils/util';
import { errlogger, infologger, loadLogger } from './app/util/logger';
import { connectThinkingData, getTire } from './app/services/sdkService';
import { loadGmDb } from './app/db';
import { loadActivities } from './app/services/activity/activityRemoteService';
import { checkAndSetApiIsClose } from './app/services/chatService';
import { initGuildActivityIndexInPinus, resetJoinWoodenHorse } from './app/services/guildActivity/guildActivityService';
import { setGVGConfig, setGVGServerGroup } from './app/services/gvg/gvgService';
import { isDevelopEnv } from './app/services/utilService';
import { initTeamToMem } from './app/services/gvg/gvgBattleMemory';

const filePath = (_pinus as any).FILEPATH;
filePath.MASTER = '/config/master';
filePath.SERVER = '/config/servers';
filePath.CRON = '/config/crons';
filePath.LOG = '/config/log4js';
filePath.SERVER_PROTOS = '/config/serverProtos';
filePath.CLIENT_PROTOS = '/config/clientProtos';
filePath.MASTER_HA = '/config/masterha';
filePath.LIFECYCLE = '/lifecycle';
filePath.SERVER_DIR = '/app/servers/';
filePath.CONFIG_DIR = '/config';

const adminfilePath = _pinus.DEFAULT_ADMIN_PATH;
adminfilePath.ADMIN_FILENAME = 'adminUser';
adminfilePath.ADMIN_USER = 'config/adminUser';
const ALL_ENVS = 'stable|development|alpha|dev|isbn|monitor|monitor2|distribute|sq1|sq3|sq4|sq7|sq9';
/**
 *  替换全局Promise
 *  自动解析sourcemap
 *  捕获全局错误
 */
preload();

/**
 * Init app for client.
 */
let app = pinus.createApp();
app.set('name', 'zyz');

// 全局配置，对所有 env 所有 serverType 生效
app.configure(function () {
    app.loadConfig('database', app.getBase() + '/config/database');
    console.log('env:', app.get('env'));
    console.log('db:', app.get('database'));
    
    setupRoutes(app);
    setupFilters(app);
    connectThinkingData(app);
    loadLogger(app.getServerId());
    treatStartLogic(app);

    app.set(RESERVED.ERROR_HANDLER, errorHandler);
    app.set(RESERVED.GLOBAL_ERROR_HANDLER, globalErrorHandler);
    // RPC 启用TCP协议
    app.set('proxyConfig', {
        mailboxFactory: createTcpMailBox,
        //    bufferMsg:true
        // rpc 超时时间
        // timeout: 20 * 1000,
        // dynamicUserProxy: true,
    });
    app.set('remoteConfig', {
        acceptorFactory: createTcpAcceptor,
        // bufferMsg:true,
        // interval:50,
    });
    app.set('serverConfig', {
        'reloadHandlers': true,
        'reloadRemotes': true,
    });
});

// 对所有 env 的 个别 serverType 进行配置
app.configure(ALL_ENVS, 'connector', function () {
    app.set('connectorConfig',
        {
            connector: pinus.connectors.hybridconnector,
            heartbeat: 60,
            useDict: false,
            useProtobuf: true
        });

    app.set('protobufConfig', {
        // protobuf Encoder 使用 5m 的缓存 需要保证每个消息不会超过指定的缓存大小，超过了就会抛出异常
        encoderCacheSize: 5 * 1024 * 1024,
        // decode 对客户端请求消息做校验
        decodeCheckMsg: true,
    });
});

// wss加密
// app.configure('sq1', 'connector', function() {
//     app.set('connectorConfig',
//         {
//             connector: pinus.connectors.hybridconnector,
//             heartbeat: 60,
//             useDict: true,
//             useProtobuf: true,
//             ssl: {
//                 type: 'wss',
//                   key: fs.readFileSync('/usr/local/nginx/conf/cert/*.37wan.com.key'),
//                   cert: fs.readFileSync('/usr/local/nginx/conf/cert/*.37wan.com_with_chain.crt'),
//               }
//         });
// });

app.configure(ALL_ENVS, 'gate', function () {
    app.set('connectorConfig',
        {
            connector: pinus.connectors.hybridconnector,
            useProtobuf: true
        });
});

app.configure(ALL_ENVS, 'guild', function () {
    app.filter(guildAuthFilter(app));
})

app.configure(ALL_ENVS, 'gm', function () {
    app.filter(tokenFilter(app));
});


function errorHandler(err: Error, msg: any, resp: any,
    session: FrontendOrBackendSession, cb: HandlerCallback) {
    const errCode = genCode(10);
    if(err.message == 'globalFilter') {
        infologger.debug('global after ', msg && msg.logCode, msg && JSON.stringify(msg),  resp && JSON.stringify(resp), session && session.get('roleId'));
    } else {
        errlogger.error(`${pinus.app.serverId} error handler \n msg[${JSON.stringify(msg)}] \n resp[${JSON.stringify(resp)}] \n sessionId:${JSON.stringify(session.export())} \n error 【${errCode}】 stack: ${err.stack}`);
    }

    if (!resp) {
        resp = resResult(STATUS.GLOBAL_ERR, { errCode, stack: err.stack });
    }
    cb(err, resp);
}

export function globalErrorHandler(err: Error, msg: any, resp: any,
    session: FrontendOrBackendSession, cb: HandlerCallback) {
    const errCode = genCode(10);
    errlogger.error(`${pinus.app.serverId} globalErrorHandler handler \n msg[${JSON.stringify(msg)}] \n resp[${JSON.stringify(resp)}] \n sessionId:${JSON.stringify(session.export())} \n error 【${errCode}】 stack: ${err.stack}`);

    if (cb) {
        cb(err, resp ? resp : { code: 503 });
    }
}

async function treatStartLogic(app: _pinus.Application) {
    await connectDb(app);
    console.log('treatStartLogic', app.getServerType());
    
    if(app.getServerType() == 'systimer') {
        redisService.redisSubScribe();
        timeTaskService.init();
        initGuildActivityIndexInPinus();
    }
    if(app.getServerType() == 'chat' && !isDevelopEnv()) {
        getTire();
    }
    if(app.getServerType() == 'activity') {
        loadActivities();
    }
    treatStartMainten(app);
    checkAndSetApiIsClose();
    if(app.getServerType() == 'guild') {
        initGuildActivityIndexInPinus()
        .then(resetJoinWoodenHorse);
    }
    if(app.getServerType() == 'battle'|| app.getServerType() == 'role'|| app.getServerType() == 'connector') {
        timeTaskService.setPvpSeasonNum();
        timeTaskService.setPvpSettleSeasonNum();
    }
    if(app.getServerType() != 'systimer') {
        timeTaskService.initHiddenData();
    }
    if(app.getServerType() == 'guild'|| app.getServerType() == 'chat'|| app.getServerType() == 'connector' || app.getServerType() == 'systimer'  || app.getServerType() == 'gm') {
        setGVGServerGroup();
    }
    if(app.getServerType() == 'guild') {
        setGVGConfig()
        app.event.on('start_all', () => {
            setGVGConfig().then(initTeamToMem);
        });
    }

    if(app.isMaster()) {
        redisService.initAllRank();
        redisService.readDataBase();
        redisService.clearComBtlQueue();
        redisService.clearChannelServers();
        redisService.clearGVGHistoryAreas();
        redisService.clearGVGHistoryAreaTeam();
        redisService.clearGVGHistoryCityTeam();
        updateTeamStatus(COM_TEAM_STATUS.DEFAULT, COM_TEAM_STATUS.LOOSE);
        updateTeamStatus(COM_TEAM_STATUS.FIGHTING, COM_TEAM_STATUS.LOOSE);
    }
}

async function treatStartMainten(app: _pinus.Application) {
    if(app.getServerType() == 'systimer') {
        // 维护信息
        await timeTaskService.initMaintenance(null, true);
    } else {
        await timeTaskService.initMaintenanaceInOtherServers();
    }
}

async function connectDb(app: _pinus.Application) {
    // Promise并行处理
    return Promise.all([ 
        initMongodb(app),
        initGmMongodb(app),
        initRedis(app)
    ])
}

async function initMongodb(app: _pinus.Application) {
    await mongoose.connect(app.get('database').mongo, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false }, (err) => {
        if (err) {
            errlogger.error('mongodb connect err', err);
        } else {
            console.log('mongodb connect suc');
        }
    });
}

async function initGmMongodb(app: _pinus.Application) {
    let gmconnect = await mongoose.createConnection(app.get('database').gmmongo, { useNewUrlParser: true, useUnifiedTopology: true, useCreateIndex: true, useFindAndModify: false });
    loadGmDb(gmconnect);
    console.log('mongoGmDb connect suc')
}
function initRedis(app: _pinus.Application) {
    const redisClient = connectRedis(app.get('database').redis, app.get('database').redispw);
    app.set('redis', redisClient);
    const redisClientPub = connectRedis(app.get('database').redis, app.get('database').redispw);
    app.set('redisPub', redisClientPub); // 发布订阅机
    redLockService.initRedlock(redisClient);
    redlockCacheService.init();
}

function setupRoutes(app: _pinus.Application) {
    app.route('chat', routeUtil.chat);
    app.route('battle', routeUtil.battle);
    app.route('gm', routeUtil.gm);
    app.route('guild', routeUtil.guild);
    app.route('activity', routeUtil.activity);
    app.route('order', routeUtil.order);
    app.route('role', routeUtil.role);
}

function setupFilters(app: _pinus.Application) {
    // filter configures
    app.filter(new pinus.filters.time());
    app.filter(new pinus.filters.timeout());

    app.filter(globalFilter(app));
    app.globalAfter((err: Error, routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, resp: any, cb: HandlerCallback) => {
        if (err) infologger.debug(err);
    })

    app.globalBefore((routeRecord: RouteRecord, msg: any, session: FrontendOrBackendSession, cb: HandlerCallback) => {
        if (msg.body === null) {
            cb(new Error(`msg body ===null maybe protobuf check error uid:${session.uid} ${JSON.stringify(msg)}`), { code: 499 });
            return;
        }
        cb(null);
    });
}

// TODO: 所有环境打开监听模块和日志
app.configure(function () {
    // enable the system monitor modules
    app.enable('systemMonitor');
    app.enable('rpcDebugLog');
});

if (app.isMaster()) {
    //   app.use(createRobotPlugin({scriptFile: __dirname + '/robot/robot.js'}));



    app.event.on('add_servers', (server) => {
        redisService.setConnectors(server); 
    })
    app.event.on('replace_servers', (server) => {
        redisService.setConnectors(server);
    })
    app.event.on('remove_servers', (server) => {
        redisService.removeConnectors(server);
    })
    app.event.on('start_all', () => {
        // 全部服务器启动完毕后初始化 redis 数据
        redisService.checkConnectors();
    });
}

// start app
app.start();
