import { Application, BackendSession, pinus, HandlerService, } from "pinus";
import { resResult, parseGoodStr, getRandSingleEelm } from "../../../pubUtils/util";
import { STATUS, TASK_FUN_TYPE, SHOP_REFRESH_TYPE, KING_EXP_RATIO_TYPE, DEBUG_MAGIC_WORD, ITEM_CHANGE_REASON, ACTIVITY_TYPE, TASK_TYPE, PUSH_ROUTE } from "../../../consts";
import { gameData } from "../../../pubUtils/data";
import { UserTaskRecModel } from "../../../db/UserTaskRec";
import { addItems } from "../../../services/role/rewardService";
import { UserTaskModel } from "../../../db/UserTask";
import { nowSeconds, getZeroPointD } from "../../../pubUtils/timeUtil";
import { DicDailyTask, DicAchievement, DicMainTask } from "../../../pubUtils/dictionary/DicTask";
import { getMainTask, refDailyTaskBox, removeHistoryTask, getCurTask, checkTask, getPvpTask } from "../../../services/task/taskService";
import { TASK } from "../../../pubUtils/dicParam";
import { ActivityTaskPointModel, ActivityTaskPointModelType } from "../../../db/ActivityTaskPoint";
import { ItemInter, RewardInter } from "../../../pubUtils/interface";
import { RoleModel } from "../../../db/Role";
import { roleLevelup } from "../../../services/normalBattleService";
import _ = require("underscore");
import { addActvityTaskPoint } from "../../../services/activity/activityService";
import { CheckTask } from "../../../services/task/taskObj";
import { ServerlistModel } from "../../../db/Serverlist";
import { sendMessageToUserWithSuc } from "../../../services/pushService";

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

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

    public async getTaskList(msg: {}, session: BackendSession) {
        const roleId: string = session.get('roleId');

        const res = await getCurTask(roleId, session);
        return resResult(STATUS.SUCCESS, res);
    }

    public async getPvpTaskList(msg: {}, session: BackendSession) {
        const roleId: string = session.get('roleId');

        const res = await getPvpTask(roleId);
        return resResult(STATUS.SUCCESS, res);
    }

    // 领取主线任务、每日任务、成就单条任务
    async receiveTask(msg: { type: number, id: number }, session: BackendSession) {
        const roleId: string = session.get('roleId');
        const serverId: number = session.get('serverId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const { type, id } = msg;

        let dicTask = gameData.tasks.get(type).get(id);
        let { group, taskType, taskReward, condition } = dicTask;
        // 检查
        let rec = await UserTaskRecModel.findByRoleAndGroup(roleId, type, taskType, group);
        if (!rec) return resResult(STATUS.TASK_NOT_REACH_CONDITION);
        if (rec.count < condition) return resResult(STATUS.TASK_NOT_REACH_CONDITION);
        if (rec.received.includes(id)) return resResult(STATUS.TASK_HAS_RECEIVED);

        // 领取记录
        rec = await UserTaskRecModel.receiveTask(roleId, type, taskType, group, id);

        // 每日、成就增加积分
        let point = 0, weeklyPoint = 0, expItem: RewardInter;
        if (type == TASK_FUN_TYPE.DAILY) { // 增加积分
            let userTask = await UserTaskModel.findByRole(roleId);
            let dic = <DicDailyTask>dicTask;
            let curWeek = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
            if (curWeek > userTask.dailyTaskRefWeekly) {
                userTask = await UserTaskModel.resetDailyScore(roleId, dic.point, curWeek);
            } else {
                userTask = await UserTaskModel.incInfo(roleId, { dailyTaskPoint: dic.point, dailyTaskPointWeekly: dic.point });
            }
            point = userTask.dailyTaskPoint;
            weeklyPoint = userTask.dailyTaskPointWeekly;
            expItem = { id: dic.exp.id, count: dic.exp.count };
        } else if (type == TASK_FUN_TYPE.ACHIEVEMENT) {
            let dic = <DicAchievement>dicTask;
            let userTask = await UserTaskModel.incInfo(roleId, { achievementPoint: dic.point });
            point = userTask.achievementPoint;
        }

        //任务完成后关联活动的积分

        await addActvityTaskPoint(type, id, session );

        let goods = await addItems(roleId, roleName, sid, taskReward, ITEM_CHANGE_REASON.TASK_REWARD);
        if (expItem && expItem.count > 0) {
            await roleLevelup(KING_EXP_RATIO_TYPE.TASK, roleId, expItem.count, session);
            goods.push(expItem);
        }

        return resResult(STATUS.SUCCESS, {
            type, id, count: rec.count, received: rec.received.includes(id),
            point, weeklyPoint,
            goods
        });
    }

    // 领取主线阶段奖励
    async receiveMainStage(msg: { stage: number }, session: BackendSession) {

        const roleId: string = session.get('roleId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const { stage } = msg;

        let dicMainStage = gameData.mainTaskStage.get(stage);
        if (!dicMainStage) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        // 检查
        let userTask = await UserTaskModel.findByRole(roleId);
        if (userTask.mainTaskStage != stage) {
            return resResult(STATUS.WRONG_PARMS);
        }
        let recs = await UserTaskRecModel.getReceiveRec(roleId, TASK_FUN_TYPE.MAIN);
        for (let id of dicMainStage.mainTaskId) {
            let curRecs = recs.find(cur => cur.received.includes(id));
            if (!curRecs) return resResult(STATUS.TASK_NOT_ALL_RECEIVED);
        }
        // 更新数据
        userTask = await UserTaskModel.incInfo(roleId, { mainTaskStage: 1 });

        let goods = await addItems(roleId, roleName, sid, dicMainStage.reward, ITEM_CHANGE_REASON.TASK_STAGE_REWARD);
        let mainTask = await getMainTask(roleId, userTask);

        return resResult(STATUS.SUCCESS, {
            type: TASK_FUN_TYPE.MAIN,
            ...mainTask,
            goods
        });
    }

    // 领取每日活跃奖励
    async receiveActiveReward(msg: {}, session: BackendSession) {

        const roleId: string = session.get('roleId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');

        // 检查
        let userTask = await UserTaskModel.findByRole(roleId);
        let { dailyTaskPoint } = userTask;
        if (dailyTaskPoint < TASK.DAILYTASK_POINT) {
            return resResult(STATUS.TASK_ACTIVE_NOT_ENOUGH);
        }
        // 更新数据
        userTask = await UserTaskModel.decreaseDailyPoint(roleId, TASK.DAILYTASK_POINT);
        if (!userTask) return resResult(STATUS.TASK_ACTIVE_NOT_ENOUGH);

        let reward = parseGoodStr(TASK.DAILYTASK_POINT_REWARD);
        let goods = await addItems(roleId, roleName, sid, reward, ITEM_CHANGE_REASON.TASK_ACTIVE_REWARD);

        return resResult(STATUS.SUCCESS, {
            type: TASK_FUN_TYPE.DAILY,
            point: userTask.dailyTaskPoint,
            goods
        });
    }

    // 领取每日周宝箱
    async receiveBox(msg: { type: number, id: number }, session: BackendSession) {
        const roleId: string = session.get('roleId');
        const roleName: string = session.get('roleName');
        const sid: string = session.get('sid');
        const { type, id } = msg;

        let userTask = await UserTaskModel.findByRole(roleId);
        let dicTaskBox = gameData.taskBox.get(type)?.get(id);
        if (!dicTaskBox) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        let point = 0, weeklyPoint = 0, box: number[] = [];
        // 每日、成就增加积分
        if (type == TASK_FUN_TYPE.DAILY) { // 增加积分
            let curWeek = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
            let shouldRefresh = false;
            let { dailyTaskPointWeekly, dailyTaskBox, dailyTaskRefWeekly } = userTask;

            if (curWeek > dailyTaskRefWeekly) {
                shouldRefresh = true;
                dailyTaskPointWeekly = 0;
                dailyTaskBox = [];
            }
            if (dailyTaskPointWeekly < dicTaskBox.point) return resResult(STATUS.TASK_ACTIVE_NOT_ENOUGH);
            if (dailyTaskBox.includes(id)) return resResult(STATUS.TASK_BOX_HAS_RECEIVED);

            userTask = await UserTaskModel.pushDailyBox(roleId, id, curWeek, shouldRefresh);

            point = userTask.dailyTaskPoint;
            box = userTask.dailyTaskBox;
            weeklyPoint = userTask.dailyTaskPointWeekly;

        } else if (type == TASK_FUN_TYPE.ACHIEVEMENT) {
            let { achievementPoint, achievementBox } = userTask;
            if (achievementPoint < dicTaskBox.point) return resResult(STATUS.TASK_ACTIVE_NOT_ENOUGH);
            if (achievementBox.includes(id)) return resResult(STATUS.TASK_BOX_HAS_RECEIVED);

            userTask = await UserTaskModel.pushAchievementBox(roleId, id);

            point = userTask.achievementPoint;
            box = userTask.achievementBox;
        } else {
            return resResult(STATUS.WRONG_PARMS);
        }

        let goods = await addItems(roleId, roleName, sid, dicTaskBox.reward, ITEM_CHANGE_REASON.TASK_BOX_REWARD);

        return resResult(STATUS.SUCCESS, {
            type,
            point, weeklyPoint, box,
            goods
        });
    }

    /**
    * @description 随机完成某一个任务
    * @param {{ type: number }} msg
    * @param {BackendSession} session
    * @memberof TaskHandler
    */
    async debugCompleteRandTask(msg: { type: number }, session: BackendSession) {
        const roleId: string = session.get('roleId');
        const sid: string = session.get('sid');
        const serverId: number = session.get('serverId');
        
        const { type } = msg
        let tasks: (DicMainTask | DicDailyTask | DicAchievement)[] = [];
        for (let [_id, task] of gameData.tasks.get(type)) {
            tasks.push(task);
        }
        let task = getRandSingleEelm(tasks);
        await checkTask(serverId, roleId, sid, task.taskType, { debugInfo: {condition: task.condition} });
        return resResult(STATUS.SUCCESS, {
            task
        });
    }

    async debugRefTask(msg: { type: number }, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        let { type } = msg
        let userTask;
        if (type == TASK_FUN_TYPE.DAILY) {
            // 转移每日任务
            await removeHistoryTask(roleId, type, new Date(nowSeconds() * 1000 + 86400000));
            sendMessageToUserWithSuc(roleId, PUSH_ROUTE.DAILY_TASK_REFRESH, { taskList: [] }, sid);
            await refDailyTaskBox(roleId, sid, true);
            userTask = await UserTaskModel.updateInfo(roleId, { dailyTaskPoint: 0 });

        } else if (type == TASK_FUN_TYPE.MAIN) {
            await UserTaskModel.updateInfo(roleId, { mainTaskStage: 1 });
            userTask = await removeHistoryTask(roleId, type, new Date(nowSeconds() * 1000 + 86400000));
        } else if (type == TASK_FUN_TYPE.ACHIEVEMENT) {
            await UserTaskModel.updateInfo(roleId, { achievementBox: [], achievementPoint: 0 });
            userTask = await removeHistoryTask(roleId, type, new Date(nowSeconds() * 1000 + 86400000));
        } else if (type == TASK_FUN_TYPE.PVP) {
            userTask = await removeHistoryTask(roleId, type, new Date(nowSeconds() * 1000 + 86400000));
        }

        let curTask = await getCurTask(roleId, session);;
        return resResult(STATUS.SUCCESS, curTask);
    }

    async debugCompleteMainStage(msg: {}, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');


        // 检查
        let userTask = await UserTaskModel.findByRole(roleId);
        let stage = userTask.mainTaskStage;

        let dicMainStage = gameData.mainTaskStage.get(stage);
        if (!dicMainStage) return resResult(STATUS.DIC_DATA_NOT_FOUND);

        let recs = await UserTaskRecModel.getReceiveRec(roleId, TASK_FUN_TYPE.MAIN);
        for (let id of dicMainStage.mainTaskId) {
            let dicTask = gameData.tasks.get(TASK_FUN_TYPE.MAIN)?.get(id);
            if (!dicTask) continue;
            let curRecs = recs.find(cur => cur.received.includes(id));
            if (!curRecs) {
                await UserTaskRecModel.setTaskRec(roleId, TASK_FUN_TYPE.MAIN, dicTask.taskType, dicTask.group, dicTask.condition);
            };
        }
        let mainTask = await getMainTask(roleId, userTask);
        for (let t of mainTask.taskList) {
            let dicTask = gameData.tasks.get(TASK_FUN_TYPE.MAIN)?.get(t.id);
            await UserTaskRecModel.setTaskRec(roleId, TASK_FUN_TYPE.MAIN, dicTask.taskType, dicTask.group, dicTask.condition);
        }
        return resResult(STATUS.SUCCESS, { mainTask });
    }

    async debugIncPoint(msg: { type: number, point: number }, session: BackendSession) {
        let roleId = session.get('roleId');
        let sid = session.get('sid');
        let { type, point: incPoint } = msg;


        // 每日、成就增加积分
        let point = 0, weeklyPoint = 0;
        if (type == TASK_FUN_TYPE.DAILY) { // 增加积分
            let userTask = await UserTaskModel.findByRole(roleId);
            let curWeek = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
            if (curWeek > userTask.dailyTaskRefWeekly) {
                userTask = await UserTaskModel.resetDailyScore(roleId, incPoint, curWeek);
            } else {
                userTask = await UserTaskModel.incInfo(roleId, { dailyTaskPoint: incPoint, dailyTaskPointWeekly: incPoint });
            }
            point = userTask.dailyTaskPoint;
            weeklyPoint = userTask.dailyTaskPointWeekly;
        } else if (type == TASK_FUN_TYPE.ACHIEVEMENT) {
            let userTask = await UserTaskModel.incInfo(roleId, { achievementPoint: incPoint });
            point = userTask.achievementPoint;
        }

        return resResult(STATUS.SUCCESS, {
            type, point, weeklyPoint
        });
    }


    async debugGetDicTask(msg: { magicWord: string }, session: BackendSession) {
        const { magicWord } = msg;
        if (magicWord !== DEBUG_MAGIC_WORD) {
            return resResult(STATUS.TOKEN_ERR);
        }
        // console.log('******', _.isEqual([1,2], [1,2,2]))
        return resResult(STATUS.SUCCESS, { tasks: [...gameData.taskType]});
    }

    async test(msg: { magicWord: string }, session: BackendSession) {
        let roleId = session.get('roleId');
        let serverId = session.get('serverId');
        let sid = session.get('sid');
        let role = await RoleModel.findByRoleId(roleId);
        let server = await ServerlistModel.findByServerId(serverId);
        return resResult(STATUS.SUCCESS)
    }
}