import { Application, BackendSession, HandlerService, } from "pinus";
import { resResult, shouldRefresh, getRandSingleEelm } from "../../../pubUtils/util";
import { STATUS, GACHA_ID, HERO_QUALITY_TYPE, TASK_TYPE, } from "../../../consts";
import { gameData } from "../../../pubUtils/data";
import { GachaResult, GachaData } from "../../../domain/activityField/gachaField";
import { UserGachaModel } from "../../../db/UserGacha";
import { refreshGacha, getGachaList, getVisitedHeroList, getAllHeroByQuality, GachaPull } from "../../../services/activity/gachaService";
import { RoleModel } from "../../../db/Role";
import { HeroModel } from "../../../db/Hero";
import { handleCost, createHeroes, addItems } from "../../../services/rewardService";
import { getZeroPointD, getTimeFun } from "../../../pubUtils/timeUtil";
import { UserGachaRecModel } from "../../../db/UserGachaRec";
import { ActivityModel } from "../../../db/Activity";
import { checkActivityTask, checkTask } from "../../../services/taskService";
import { RECRUIT } from "../../../pubUtils/dicParam";
import { getActivityById } from "../../../services/activity/activityService";

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

export class GachaHandler {
    constructor(private app: Application) {
    }

    /**
    * @description 获取抽卡列表 元宝招募、友情点招募、求贤若渴
    * @param {{}} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async getGachaList(msg: {}, session: BackendSession) {
        const { } = msg;
        const roleId: string = session.get('roleId');
        const list = await getGachaList(roleId);

        return resResult(STATUS.SUCCESS, { list });
    }

    /**
    * @description 抽卡，所有抽卡类型都
    * @param {{ gachaId: number, activityId: number, count: number }} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async pull(msg: { gachaId: number, activityId: number, count: number }, session: BackendSession) {
        const { gachaId, activityId, count } = msg;
        if (gachaId == undefined || activityId == undefined || count == undefined) return resResult(STATUS.WRONG_PARMS);
        const roleId: string = session.get('roleId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const serverId: number = session.get('serverId');
        

        let { lv } = await RoleModel.findByRoleId(roleId);

        let dicGacha = gameData.gacha.get(gachaId);
        if (!dicGacha) return resResult(STATUS.DIC_DATA_NOT_FOUND);
        if (!dicGacha.count.includes(count)) return resResult(STATUS.WRONG_PARMS);

        let userGacha = await UserGachaModel.findByRole(roleId, gachaId, activityId);
        userGacha = await refreshGacha(dicGacha, userGacha);
        let { freeCount, point, pickHero, refFreeTime, count: historyCount } = userGacha;
        if ((gachaId == GACHA_ID.ASSIGN || gachaId == GACHA_ID.TIMELIMIT) && !pickHero) return resResult(STATUS.GACHA_NOT_ASSIGN);

        let userHeroes = await HeroModel.findByRole(roleId);

        let gachaPull = new GachaPull(gachaId, lv, userHeroes);
        gachaPull.setByUserGacha(dicGacha, userGacha);
        let { items, heroInfo, resultList, activityData } = gachaPull.pull(count);
        let { hope, floor } = gachaPull.getUserGachaParam(userGacha);

        let costNum = count;
        if (count == 1 && dicGacha.free.count > 0) { // 单抽的时候免费
            if (count > dicGacha.free.count - freeCount) {
                costNum = count - dicGacha.free.count + freeCount;
                freeCount = dicGacha.free.count;
            } else {
                costNum = 0;
                freeCount += count;
            }
        }
        // 消耗东西
        if (costNum > 0) {
            let cost = dicGacha.cost.map(cur => { return { id: cur.id, count: cur.count * costNum } });
            let costResult = await handleCost(roleId, sid, cost);
            if (!costResult) return resResult(STATUS.GACHA_COST_NOT_ENOUGH);
        }
        // 给东西
        // console.log('****', heroInfo)
        let { heroes } = await createHeroes(roleId, roleName, sid, serverId, heroInfo);
        await addItems(roleId, roleName, sid, items);
        // 更新数据
        userGacha = await UserGachaModel.updateInfo(roleId, gachaId, activityId, {
            freeCount, hope, floor, count: historyCount + count
        });

        await UserGachaRecModel.createRec(roleId, gachaId, activityId, count, resultList);

        // 任务
        await checkTask(roleId, sid, TASK_TYPE.GASHA, count, true, {});
        //活动统计
        await checkActivityTask(serverId, sid, roleId, TASK_TYPE.GASHA, count)
        for (let hero of heroes) {
            activityData.push({ hid: hero.hid, quality: hero.quality });
        }
        await checkActivityTask(serverId, sid, roleId, TASK_TYPE.GACHA_QUALITY_COUNT, count, { heroes: activityData })

        let resultRefFreeTime = 0;
        if (dicGacha.free.count > 0) {
            let f = getTimeFun(userGacha.refFreeTime);
            resultRefFreeTime = <number>f.getAfterDayWithHour(dicGacha.free.day);
        }
        return resResult(STATUS.SUCCESS, {
            gachaId, activityId,
            freeCount, refFreeTime: resultRefFreeTime, count: userGacha.count, point: userGacha.point, floor, hope,
            heroes, result: resultList
        });
    }

    /**
    * @description 设置心愿单
    * @param {{ gachaId: number, hope: { id: number, hid: number }[] }} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async setHope(msg: { gachaId: number, hope: { id: number, hid: number }[] }, session: BackendSession) {
        const { gachaId, hope } = msg;
        const roleId: string = session.get('roleId');

        for (let { hid } of hope) {
            let dicHero = gameData.hero.get(hid);
            if (hid != 0) {
                if (!dicHero) return resResult(STATUS.DIC_DATA_NOT_FOUND);
                if (hid != 0 && dicHero.quality != HERO_QUALITY_TYPE.GOLD) {
                    return resResult(STATUS.GACHA_HOPE_NOT_GOLD);
                }
            }
        }
        let userGacha = await UserGachaModel.updateInfo(roleId, gachaId, 0, { hope: hope.map(cur => { return { ...cur, hasGet: false } }) })

        return resResult(STATUS.SUCCESS, {
            gachaId,
            hope: userGacha.hope
        });
    }

    /**
    * @description 转盘
    * @param {{ gachaId: number }} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async drawTurnTable(msg: { gachaId: number }, session: BackendSession) {
        const { gachaId } = msg;
        const roleId: string = session.get('roleId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const serverId: number = session.get('serverId');
        

        let userGacha = await UserGachaModel.findByRole(roleId, gachaId, 0);
        let { point, turntable, costPoint } = userGacha;
        if (point < RECRUIT.RECRUIT_BONUS_RECRUIT) return resResult(STATUS.GACHA_TURNTABLE_POINT_NOT_ENOUGH);

        let turntablePool: { quality: number, count: number }[] = [];
        for (let { quality, count } of gameData.gachaTurntable) {
            let myTurntable = turntable.find(cur => cur.quality == quality);
            if (!myTurntable || !myTurntable.hasGet) {
                turntablePool.push({ quality, count });
            }
        }
        if (turntablePool.length <= 0) { // 重置
            turntable = []; turntablePool = gameData.gachaTurntable;
        }

        let randTurntable = getRandSingleEelm(turntablePool);
        let { quality, count } = randTurntable;
        // 根据品质查武将
        let pool = getAllHeroByQuality(quality);

        let hero = getRandSingleEelm(pool);
        let contentId = gameData.gachaContentHero.get(hero);

        // 获得或者转成碎片
        let heroInfo: { hid: number, count: number }[] = [];
        for (let i = 0; i < count; i++) {
            heroInfo.push({ hid: hero, count: 1 })
        }
        let { heroes, goods } = await createHeroes(roleId, roleName, sid, serverId, heroInfo);
        let resultList: GachaResult[] = [];
        for (let h of heroes) {
            let result = new GachaResult(contentId);
            result.setHero(h.hid);
            resultList.push(result);
        }
        for (let g of goods) {
            let result = new GachaResult(contentId);
            result.setHero(hero);
            result.transferToPiece(g.id, g.count);
            resultList.push(result);
        }

        // 记录
        let myTurntable = turntable.find(cur => cur.quality == quality);
        if (!myTurntable) {
            myTurntable = { quality, hasGet: false };
            turntable.push(myTurntable);
        }
        myTurntable.hasGet = true;
        // 扣除积分
        userGacha = await UserGachaModel.updateInfo(roleId, gachaId, 0, { turntable, costPoint: costPoint + 1 });

        return resResult(STATUS.SUCCESS, {
            gachaId,
            point: userGacha.point,
            turntable: userGacha.turntable,
            result: resultList,
            heroes
        });
    }


    /**
    * @description 求贤若渴&限时招募里面设置pick武将
    * @param {{ gachaId: number, pickHero: number }} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async setPickHero(msg: { gachaId: number, activityId: number, pickHero: number }, session: BackendSession) {
        const { gachaId, activityId = 0, pickHero } = msg;
        const roleId: string = session.get('roleId');
        const serverId: number = session.get('serverId');
        if (gachaId != GACHA_ID.ASSIGN && gachaId != GACHA_ID.TIMELIMIT)
            return resResult(STATUS.WRONG_PARMS);
        let dicHero = gameData.hero.get(pickHero);
        if (!dicHero) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        let heroes: number[] = [];
        if (gachaId == GACHA_ID.TIMELIMIT) {
            let activityData = await getActivityById(activityId);
            if (!activityData) return resResult(STATUS.ACTIVITY_MISSING);

            let { createTime } = await RoleModel.findByRoleId(roleId);
            let gachaData = new GachaData(activityData, createTime);
            heroes = gachaData.heroes;
            if (!heroes.includes(pickHero)) {
                return resResult(STATUS.GACHA_CAN_NOT_PICK)
            }
        }

        let userGacha = await UserGachaModel.updateInfo(roleId, gachaId, activityId, { pickHero })

        return resResult(STATUS.SUCCESS, {
            gachaId,
            activityId,
            heroes,
            pickHero: userGacha.pickHero
        });

    }

    /**
    * @description 今天拜访过的武将
    * @param {{ }} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async getVisitedHero(msg: {}, session: BackendSession) {
        const roleId: string = session.get('roleId');

        let visitedHero = await getVisitedHeroList(roleId);

        return resResult(STATUS.SUCCESS, {
            hids: visitedHero
        });
    }

    /**
    * @description 拜访武将
    * @param {{ hid: number }} msg
    * @param {BackendSession} session
    * @memberof GachaHandler
    */
    async visitHero(msg: { hid: number }, session: BackendSession) {
        const roleId: string = session.get('roleId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const { hid } = msg;

        let dicHero = gameData.hero.get(hid);
        if (!dicHero) return resResult(STATUS.DIC_DATA_NOT_FOUND);
        let index = gameData.recruit.findIndex(cur => cur.actorId == hid);
        if (index == -1) return resResult(STATUS.GACHA_CAN_NOT_PICK);
        let { pieceId } = dicHero;

        let { visitedHero, refVisitedTime } = await UserGachaModel.findByRole(roleId, GACHA_ID.NORMAL, 0);
        if (shouldRefresh(refVisitedTime, new Date())) {
            visitedHero = [];
            refVisitedTime = getZeroPointD();
        }
        if (visitedHero.includes(hid)) {
            return resResult(STATUS.GACHA_HAS_VISITED);
        }
        if (visitedHero.length >= RECRUIT.RECRUIT_DAILY_RECRUIT_SHARD) {
            return resResult(STATUS.GACHA_VISITED_COUNT_OVER);
        }

        visitedHero.push(hid);
        let userGacha = await UserGachaModel.updateInfo(roleId, GACHA_ID.NORMAL, 0, { visitedHero, refVisitedTime });
        let goods = await addItems(roleId, roleName, sid, [{ id: pieceId, count: RECRUIT.RECRUIT_SHARD_LIMIT }]);

        return resResult(STATUS.SUCCESS, {
            hids: userGacha.visitedHero,
            goods
        });
    }
}