import { Application, BackendSession, ChannelService, pinus, HandlerService, } from "pinus";
import { getGuildActivityStatus, getRecordScore, getGateActivityObj, participants, getGateActivityRank, getCityActivityObj, getGAIndexInPinus } from "../../../services/guildActivity/guildActivityService";
import { resResult } from "../../../pubUtils/util";
import { STATUS, GUILD_ACTIVITY_TYPE, GUILD_POINT_WAYS, ENEMIES_TYPE, GET_POINT_WAYS, TASK_TYPE, GUILD_ACTIVITY_STATUS } from "../../../consts";
import { UserGuildActivityRecModel } from "../../../db/UserGuildActivityRec";
import { GUILDACTIVITY } from "../../../pubUtils/dicParam";
import { GuildActivityRecordModel } from "../../../db/GuildActivityRec";
import { delGuildActivityRank } from "../../../services/redisService";
import { REDIS_KEY } from "../../../consts";
import { gameData } from "../../../pubUtils/data";
import { UserGuildModel } from "../../../db/UserGuild";
import { GuildActivityCityModel } from "../../../db/GuildActivityCity";
import { Rank } from "../../../services/rankService";
import { getTimeFun, getZeroPointD } from "../../../pubUtils/timeUtil";
import { checkTask } from "../../../services/task/taskService";
import { guildInter } from "../../../pubUtils/interface";
import { ServerRecordModel } from "../../../db/ServerRecords";

export default function (app: Application) {
    new HandlerService(app, {});
    return new GateActivityHandler(app);
}

export class GateActivityHandler {
    channelService: ChannelService;
    constructor(private app: Application) {
        this.channelService = app.get('channelService');
    }

    private aid = GUILD_ACTIVITY_TYPE.GATE_ACTIVITY; // 蛮夷入侵id

    // 进入蛮夷入侵界面
    async getGateActivity(msg: {}, session: BackendSession) {

        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const serverId = session.get('serverId');
        const guildCode = session.get('guildCode');
        let index = getGAIndexInPinus(this.aid);
        if (!guildCode) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);

        let statusResult = getGuildActivityStatus(this.aid);
        if (!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        let guildActivityRec = await GuildActivityRecordModel.getRecord(guildCode, serverId, this.aid, index);
        if (!guildActivityRec) return resResult(STATUS.INTERNAL_ERR);

        let { code: sourceCode } = guildActivityRec;
        let myGuildActivityRec = await UserGuildActivityRecModel.getRecord(roleId, roleName, guildCode, serverId, sourceCode, this.aid);
        let { challengeCnt } = myGuildActivityRec;

        let ranks = await getGateActivityRank(guildCode, serverId, roleId, roleName);

        return resResult(STATUS.SUCCESS, {
            ...statusResult,
            challengeCnt: GUILDACTIVITY.GATEACTIVITY_CHALLENGE_TIMES - challengeCnt,
            ...ranks
        });
    }

    // 开启挑战
    async checkBattle(msg: guildInter & { heroes: number[] }, session: BackendSession) {
        let { heroes, myUserGuild: userGuild } = msg;
        const roleId = session.get('roleId');
        const roleName = session.get('roleName');
        const serverId = session.get('serverId');
        const guildCode = session.get('guildCode');
        const sid = session.get('sid');
        if (!guildCode) return resResult(STATUS.GUILD_AUTH_NOT_ENOUGH);
        let obj = getGateActivityObj();
        let index = getGAIndexInPinus(this.aid);

        let statusResult = getGuildActivityStatus(this.aid);
        if (!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);
        if(!statusResult.isOpen) return resResult(STATUS.GUILD_ACTIVITY_NOT_OPEN);

        let guildActivityRec = await GuildActivityRecordModel.getRecord(guildCode, serverId, this.aid, index);
        if (!guildActivityRec) return resResult(STATUS.INTERNAL_ERR);

        let { code: sourceCode } = guildActivityRec;
        let myGuildActivityRec = await UserGuildActivityRecModel.getRecord(roleId, roleName, guildCode, serverId, sourceCode, this.aid);
        if (myGuildActivityRec.challengeCnt > 0) {
            return resResult(STATUS.CHALLENGE_CNT_NOT_ENOUGH);
        }
        myGuildActivityRec = await UserGuildActivityRecModel.incChallengeCnt(myGuildActivityRec.code, heroes);
        let { code, challengeCnt } = myGuildActivityRec;

        // 更新公会参与的玩家
        obj.pushMembers(guildCode, serverId, roleId, userGuild.job, code);

        // 返回当前军团总军功
        let r = new Rank(REDIS_KEY.GATE_ACTIVITY, { serverId, index }, true);
        let guildScore = await r.getMyScore({ guildCode });
        // 全服活跃统计
        await ServerRecordModel.addActiveGuild(serverId, roleId, guildCode);

        // 任务
        await checkTask(serverId, roleId, sid, TASK_TYPE.GUILD_ACTIVITY, { aid: this.aid });
        return resResult(STATUS.SUCCESS, {
            code,
            ...statusResult,
            guildScore: guildScore || 0,
            myScore: 0,
            challengeCnt: GUILDACTIVITY.GATEACTIVITY_CHALLENGE_TIMES - challengeCnt,
        });
    }

    // 上报玩家获得军功
    async action(msg: { code: string, round: number, record: { round: number, dataId: number }[] }, session: BackendSession) {
        let roleId = session.get('roleId');
        let roleName = session.get('roleName');
        let guildCode = session.get('guildCode');
        let serverId = session.get('serverId');

        let { code, round, record } = msg;
        let obj = getGateActivityObj();

        let statusResult = getGuildActivityStatus(this.aid);
        if (!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);
        if(!statusResult.isOpen) return resResult(STATUS.GUILD_ACTIVITY_NOT_OPEN);
        if(statusResult.status != GUILD_ACTIVITY_STATUS.START) {
            return resResult(STATUS.SUCCESS, {
                code,
                ...statusResult
            })
        }

        // 计算record内得分
        let memberRecord = obj.getMemberRecord(code, roleId);
        let scoreResult = getRecordScore(this.aid, round, record, memberRecord);
        if (!scoreResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);
        let { score, newRecords, memberRecord: newMemberRecord } = scoreResult;
        obj.setMemberRecord(code, newMemberRecord);

        let nextWeek = <number>getTimeFun().getAfterDayWithHour(7);
        // console.log('####### nextWeek', nextWeek)
        let index = getGAIndexInPinus(this.aid);
        // 更新redis数据
        let myR = new Rank(REDIS_KEY.USER_GATE_ACTIVITY, { serverId, guildCode, index }, true);
        let myScore = await myR.setRankWithRoleInfo(roleId, score, obj.getTimeGap(), null, true);
        await myR.setExpire(nextWeek);

        let r = new Rank(REDIS_KEY.GATE_ACTIVITY, { serverId, index }, true);
        let guildScore = await r.setRankWithGuildInfo(guildCode, score, obj.getTimeGap(), null, true);
        await r.setExpire(nextWeek);

        // 更新数据库
        let rec = await UserGuildActivityRecModel.pushRecord(code, newRecords, round);

        return resResult(STATUS.SUCCESS, {
            code: rec.code,
            ...statusResult,
            guildScore: guildScore || 0,
            myScore: myScore || 0
        });
    }

    // 结束挑战
    async battleEnd(msg: { code: string, isSuccess: boolean, gateHp: number }, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        let guildCode = session.get('guildCode');
        let serverId = session.get('serverId');

        let { code, isSuccess, gateHp } = msg;

        let statusResult = getGuildActivityStatus(this.aid);
        if (!statusResult) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        // 更新userGuildActivityRecord
        let myGuildActivityRec = await UserGuildActivityRecModel.updateInfo(code, { isSuccess, isCompleted: true, gateHp });
        if (!myGuildActivityRec) return resResult(STATUS.INTERNAL_ERR);

        // 功劳簿计算
        let { record, round } = myGuildActivityRec;
        let enemyCnt = 0, littleBossCnt = 0, bossCnt = 0;
        for (let { enemyType, round: r } of record) {
            if (enemyType == ENEMIES_TYPE.ENEMY || enemyType == ENEMIES_TYPE.ELITE_ENEMY) {
                enemyCnt++;
            } else if (enemyType == ENEMIES_TYPE.LITTLE_BOSS) {
                littleBossCnt++;
            } else if (enemyType == ENEMIES_TYPE.BOSS) {
                bossCnt++;
            }
        }

        let index = getGAIndexInPinus(this.aid);
        let myR = new Rank(REDIS_KEY.USER_GATE_ACTIVITY, { serverId, guildCode, index }, true);
        let r = new Rank(REDIS_KEY.GATE_ACTIVITY, { serverId }, true);
        if (isSuccess && statusResult.status == GUILD_ACTIVITY_STATUS.START) {
            let obj = getGateActivityObj();
            let score = gameData.gateActivityPoint.get(GET_POINT_WAYS.DEFENSE_SUCCESS);

            if(score > 0) {
                await myR.setRankWithRoleInfo(roleId, score, obj.getTimeGap(), null, true);
                await r.setRankWithGuildInfo(guildCode, score, obj.getTimeGap(), null, true);
            }
        }

        // 返回当前军团总军功
        let guildScore = await r.getMyScore({ guildCode });
        let myScore = await myR.getMyScore({ roleId });

        let info = {
            round,
            enemyCnt, littleBossCnt, bossCnt,
            isSuccess
        }

        return resResult(STATUS.SUCCESS, {
            code,
            ...statusResult,
            guildScore,
            myScore,
            info
        })
    }

    // ! 测试接口
    async debugGetPrivate(msg: {}, session: BackendSession) {
        let guildCode = session.get('guildCode');
        // console.log(guildCode);
        let serverId = session.get('serverId');
        let res = getGateActivityObj().getObj(guildCode, serverId);
        return resResult(STATUS.SUCCESS, res)
    }

    // ! 测试接口
    async test(msg: { sourceType: number, sourceCode: string }, session: BackendSession) {
        let guildCode = session.get('guildCode');
        let serverId = session.get('serverId');

        // await GuildActivityCityModel.declare(serverId, 1, guildCode);
        let { sourceType, sourceCode } = msg;
        let result = await participants(guildCode, sourceType, sourceCode);
        return result;

        // let result = await setMedianCe();
        // return resResult(STATUS.SUCCESS, {result});
    }

    // ! 测试接口
    async debugIncChallengeCnt(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let today = getZeroPointD();
        await UserGuildActivityRecModel.updateMany(
            { roleId, createdAt: { $gte: today } }, { $set: { challengeCnt: -100 } }, { new: true }).lean();

        return resResult(STATUS.SUCCESS);
    }

    // ! 测试接口
    async debugStartActivity(msg: { aid: number }, session: BackendSession) {
        let { aid } = msg;
        let dic = gameData.guildActivity.get(aid);
        if (!dic) return resResult(STATUS.WRONG_PARMS);
        let result = await pinus.app.rpc.systimer.systimerRemote.guildActivityStart.toServer('systimer-server-1', dic);
        if (!result) {
            return resResult(STATUS.GUILD_ACTIVITY_IS_OPEN)
        }

        // !! 注意，这条函数会改变内存中的字典表，仅用于测试中使用
        let now = new Date();
        let guildServers = pinus.app.getServersByType('guild');
        for (let server of guildServers) {
            pinus.app.rpc.guild.guildActivityRemote.updateGuildActivityData.toServer(server.id, aid, true);
        }

        return resResult(STATUS.SUCCESS);
    }

    // ! 测试接口
    async debugSetDay(msg: { week: number }, session: BackendSession) {
        await pinus.app.rpc.guild.guildActivityRemote.setDay.broadcast(msg.week);
        await pinus.app.rpc.systimer.systimerRemote.setDay.broadcast(msg.week);
        await pinus.app.rpc.connector.connectorRemote.setDay.broadcast(msg.week);

        if (msg.week <= 2) {
            await GuildActivityCityModel.deleteMany({});
        }
        await delGuildActivityRank(GUILD_ACTIVITY_TYPE.GATE_ACTIVITY);
        await delGuildActivityRank(GUILD_ACTIVITY_TYPE.CITY_ACTIVITY);
        await delGuildActivityRank(GUILD_ACTIVITY_TYPE.RACE_ACTIVITY);
        return resResult(STATUS.SUCCESS);
    }

    // ! 测试接口
    async debugEndActivity(msg: { aid: number }, session: BackendSession) {
        let { aid } = msg;
        if (aid == GUILD_ACTIVITY_TYPE.GATE_ACTIVITY) {
            await pinus.app.rpc.systimer.systimerRemote.gateActivityEnd.toServer('systimer-server-1');
        } else if (aid == GUILD_ACTIVITY_TYPE.CITY_ACTIVITY) {
            await pinus.app.rpc.systimer.systimerRemote.cityActivityEnd.toServer('systimer-server-1');
        } else if (aid == GUILD_ACTIVITY_TYPE.RACE_ACTIVITY) {
            await pinus.app.rpc.systimer.systimerRemote.raceActivityEnd.toServer('systimer-server-1');
        } else {
            return resResult(STATUS.WRONG_PARMS)
        }

        // !! 注意，这条函数会改变内存中的字典表，仅用于测试中使用
        let now = new Date();
        let guildServers = pinus.app.getServersByType('guild');
        for (let server of guildServers) {
            pinus.app.rpc.guild.guildActivityRemote.updateGuildActivityData.toServer(server.id, aid, false);
        }
        return resResult(STATUS.SUCCESS);
    }

    async debugDelRedis(msg: { aid: number }, session: BackendSession) {
        let { aid } = msg;
        await delGuildActivityRank(aid);
    }

    // ! 测试接口 将自己添加进活动roleId里
    async debugAddParticipants(msg: { aid: number }, session: BackendSession) {
        let roleId = session.get('roleId');
        let guildCode = session.get('guildCode');
        if (!guildCode) return resResult(STATUS.GUILD_NOT_FOUND);
        let serverId = session.get('serverId');
        let { aid } = msg;
        let index = getGAIndexInPinus(aid);
        await GuildActivityRecordModel.getRecord(guildCode, serverId, aid, index);
        let userGuild = await UserGuildModel.getMyGuild(roleId);
        let result = await GuildActivityRecordModel.updateInfo(guildCode, aid, index, { memberCnt: 1, members: [{ roleId, job: userGuild.job, code: '' }], auctionType: aid + 1 });

        return resResult(STATUS.SUCCESS, {
            sourceType: result.auctionType,
            sourceCode: result.code
        });
    }
}
