import * as taskUtil from '../pubUtils/taskUtil';
import { RoleModel, RoleType } from '../db/Role';
import { pinus, FrontendOrBackendSession } from 'pinus';
import { resResult, shouldRefresh } from '../pubUtils/util';
import { STATUS, TASK_TYPE, TASK_FUN_TYPE, SHOP_REFRESH_TYPE, WAR_TYPE } from '../consts';
import { TaskParam, TaskListReturn } from '../domain/roleField/task';
import { HeroType } from '../db/Hero';
import { EquipType } from '../db/Equip';
import { getRoleOnlineInfo } from './redisService';
import { HeroScores } from '../db/PvpHistoryOpp';
import { ItemInter } from '../pubUtils/interface';
import { UserTaskModel, UserTaskType } from '../db/UserTask';
import { UserTaskRecModel } from '../db/UserTaskRec';
import { UserTaskHistoryModel } from '../db/UserTaskHistory';
import { gameData, getGoodById } from '../pubUtils/data';
import { getSeconds, getZeroPointD } from '../pubUtils/timeUtil';
import { RoleStatus } from '../db/ComBattleTeam';
import { getActivities } from './activity/activityService';

export async function checkTaskWithRoles(serverId: number, roleId: string, sid: string, taskType: number, roles: RoleType[]) {
    for (let role of roles) {
        if (role) {
            await checkTaskWithRole(serverId, role.roleId, role.roleId == roleId ? sid : null, taskType, role);
        }
    }
}

export async function checkTaskWithRole(serverId: number, roleId: string, sid: string, taskType: number, role: RoleType) {
    let pushMessage = await taskUtil.checkTaskWithRole(serverId, roleId, taskType, role);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function checkTaskWithHero(roleId: string, sid: string, taskType: number, hero: HeroType, args?: number[]) {
    let pushMessage = await taskUtil.checkTaskWithHero(roleId, taskType, hero, args);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function checkTaskWithEquip(roleId: string, sid: string, taskType: number, equip: EquipType, args?: number[]) {
    let pushMessage = await taskUtil.checkTaskWithEquip(roleId, taskType, equip, args);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function checkTaskWithArgs(roleId: string, sid: string, taskType: number, args: number[]) {
    let pushMessage = await taskUtil.checkTaskWithArgs(roleId, taskType, args);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function checkTaskWithWar(roleId: string, sid: string, taskType: number, warId: number, heroes: number[], count: number, star: number) {
    let pushMessage = await taskUtil.checkTaskWithWar(roleId, taskType, warId, heroes, count, star);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function checkTaskWithGoods(roleId: string, sid: string, taskType: number, goods: ItemInter[]) {
    let pushMessage = await taskUtil.checkTaskWithGoods(roleId, taskType, goods);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function checkTask(roleId: string, sid: string, taskType: number, count: number, isInc: boolean, param: TaskParam) {
    let pushMessage = await taskUtil.checkTask(roleId, taskType, count, isInc, param);
    pushTaskUpdate(roleId, sid, pushMessage);
}

export async function pushTaskUpdate(roleId: string, sid: string, pushMessage: TaskListReturn[]) {
    if (pushMessage.length > 0) {
        if (!sid) {
            let onlineUser = await getRoleOnlineInfo(roleId);
            sid = onlineUser.sid;
        }
        if (!!sid) {
            let uids = [{ uid: roleId, sid }];
            pinus.app.get('channelService').pushMessageByUids('onTaskUpdate', resResult(STATUS.SUCCESS, pushMessage), uids);
        }
    }
}


export async function checkActivityTask(serverId: number, sid: string, roleId: string, taskType: TASK_TYPE, count: number, parma?: any) {
    let pushMessage = await taskUtil.accomplishTask(serverId, roleId, taskType, count, parma, await getActivities());
    pushActivityUpdate(roleId, sid, pushMessage);
    return pushMessage;
}

export async function pushActivityUpdate(roleId: string, sid: string, pushMessage: any[]) {
    console.log('pushActivityUpdate', JSON.stringify(pushMessage))
    if (pushMessage.length > 0) {
        if (!sid) {
            let onlineUser = await getRoleOnlineInfo(roleId);
            sid = onlineUser.sid;
        }
        if (!!sid) {
            let uids = [{ uid: roleId, sid }];
            pinus.app.get('channelService').pushMessageByUids('onActivityUpdate', resResult(STATUS.SUCCESS, pushMessage), uids);
        }
    }
}

/**
 * battle.normalBattleHandler.battleEnd 中会触发的任务，因为有点多提出来了
 */
export async function checkTaskInBattleEnd(serverId: number, roleId: string, sid: string, battleId: number, heroes: number[], star: number) {

    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_WITH_HERO, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_MAIN, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_DAILY_STAR, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_DAILY, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_DUNGEON, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_DUNGEON_WAR, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_TOWER, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_VESTIGE, battleId, heroes, 1, star);
    await checkTaskWithWar(roleId, sid, TASK_TYPE.BATTLE_EXPEDITION, battleId, heroes, 1, star);
    //成长任务
    let dicWar = gameData.war.get(battleId);
    if (dicWar) {
        if (dicWar.warType == WAR_TYPE.NORMAL) {
            await checkActivityTask(serverId, sid, roleId, TASK_TYPE.BATTLE_MAIN, 1, { warId: battleId })
        } else if (dicWar.warType == WAR_TYPE.EXPEDITION) {
            await checkActivityTask(serverId, sid, roleId, TASK_TYPE.BATTLE_EXPEDITION, 1)
        } else if (dicWar.warType == WAR_TYPE.MYSTERY || dicWar.warType == WAR_TYPE.MYSTERY_ELITE) {
            await checkActivityTask(serverId, sid, roleId, TASK_TYPE.BATTLE_DUNGEON_WAR, 1, { warId: battleId })
        } else if (dicWar.warType == WAR_TYPE.TOWER) {
            await checkActivityTask(serverId, sid, roleId, TASK_TYPE.BATTLE_TOWER, 1)
        } else if (dicWar.warType == WAR_TYPE.DAILY) {
            await checkActivityTask(serverId, sid, roleId, TASK_TYPE.BATTLE_DAILY, 1, { warId: battleId })
        }
    }

}

export async function checkTaskInComBattleEnd(roleStatus: RoleStatus[], capId: string, quality: number) {
    console.log('********', JSON.stringify(roleStatus), capId, quality)
    for (let { roleId, isRobot } of roleStatus) {
        if (!isRobot) {

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

            if (roleId == capId && roleStatus.length > 1) {  // 招募队友
                await checkTask(roleId, null, TASK_TYPE.COM_BATTLE_CREATE_TEAM, 1, true, {});
            } else if (roleId !== capId) { // 协助寻宝
                await checkTask(roleId, null, TASK_TYPE.COM_BATTLE_ASSIST_TEAM, 1, true, {});
                //活动任务
                await checkActivityTask(serverId, null, roleId, TASK_TYPE.COM_BATTLE_ASSIST_TEAM, 1);
            }
            await checkTask(roleId, null, TASK_TYPE.COM_BATTLE, 1, true, {});
            await checkTask(roleId, null, TASK_TYPE.COM_BATTLE_QUALITY, 1, true, { quality });
            //活动任务
            await checkActivityTask(serverId, null, roleId, TASK_TYPE.COM_BATTLE, 1);
        }
    }
}

export async function checkTaskInPvpEnd(roleId: string, sid: string, isSuccess: boolean, heroScores: HeroScores[]) {
    await checkTask(roleId, sid, TASK_TYPE.PVP, 1, true, {});
    if (isSuccess) {
        await checkTask(roleId, sid, TASK_TYPE.PVP_WIN, 1, true, {});
        await checkTask(roleId, sid, TASK_TYPE.PVP_WIN_SERIES, 1, true, {});
    } else {
        await checkTask(roleId, sid, TASK_TYPE.PVP_WIN_SERIES, 0, false, {});
    }

    await checkTask(roleId, sid, TASK_TYPE.PVP_HERO_SCORE, 0, false, { heroScores });
}


// 获取task状态
export async function getCurTask(roleId: string, session: FrontendOrBackendSession) {
    let userTask = await UserTaskModel.findByRole(roleId);

    let { dailyTaskRefWeekly, dailyTaskRef } = userTask;
    let curWeekStart = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
    if (dailyTaskRefWeekly < curWeekStart) { // 刷新周宝箱
        dailyTaskRefWeekly = curWeekStart;
    }
    session.set('refWeekly', getSeconds(dailyTaskRefWeekly));
    session.push('refWeekly', () => { });

    if (shouldRefresh(dailyTaskRef, new Date())) {
        dailyTaskRef = new Date();
        userTask = await UserTaskModel.updateInfo(roleId, { dailyTaskRef });
        await removeHistoryTask(roleId, TASK_FUN_TYPE.DAILY);
    }
    session.set('refDaily', getSeconds(dailyTaskRef));
    session.push('refDaily', () => { });

    let mainTask = await getMainTask(roleId, userTask);
    let dailyTask = await getDailyTask(roleId, userTask);
    let achievement = await getAchievement(roleId, userTask);
    return { mainTask, dailyTask, achievement };
}

export async function getMainTask(roleId: string, userTask: UserTaskType) {
    let type = TASK_FUN_TYPE.MAIN;
    let { mainTaskStage: stage } = userTask;
    let recMap = await UserTaskRecModel.findByRoleAndType(roleId, type); // group=>userTaskRec

    let taskList: TaskListReturn[] = [];
    for (let [id, dic] of gameData.mainTask) {
        if (dic.taskStage == stage) {
            let dbRec = recMap.get(dic.taskType)?.get(dic.group);
            if (dbRec) {
                taskList.push({ type, id, count: dbRec.count, received: dbRec.received.includes(id) });
            } else {
                taskList.push({ type, id, count: 0, received: false });
            }
        }
    }
    return { stage, taskList }
}

export async function getDailyTask(roleId: string, userTask: UserTaskType) {
    let type = TASK_FUN_TYPE.DAILY;
    let { dailyTaskPoint: point, dailyTaskRefWeekly, dailyTaskPointWeekly: weeklyPoint, dailyTaskBox: box } = userTask;
    let curWeekStart = getZeroPointD(SHOP_REFRESH_TYPE.WEEKLY);
    if (dailyTaskRefWeekly < curWeekStart) { // 刷新
        dailyTaskRefWeekly = curWeekStart;
        weeklyPoint = 0;
        box = [];
    }
    let recMap = await UserTaskRecModel.findByRoleAndType(roleId, type); // group=>userTaskRec

    let taskList: TaskListReturn[] = [];
    for (let [id, dic] of gameData.dailyTask) {
        let dbRec = recMap.get(dic.taskType)?.get(dic.group);
        if (dbRec) {
            taskList.push({ type, id, count: dbRec.count, received: dbRec.received.includes(id) });
        } else {
            taskList.push({ type, id, count: 0, received: false });
        }
    }
    return { point, weeklyPoint, taskList, box }
}

export async function getAchievement(roleId: string, userTask: UserTaskType) {
    let type = TASK_FUN_TYPE.ACHIEVEMENT;
    let { achievementBox: box, achievementPoint: point } = userTask;
    let recMap = await UserTaskRecModel.findByRoleAndType(roleId, type); // group=>userTaskRec

    let taskList: TaskListReturn[] = [];
    for (let [id, dic] of gameData.achievement) {
        let dbRec = recMap.get(dic.taskType)?.get(dic.group);
        if (dbRec) {
            taskList.push({ type, id, count: dbRec.count, received: dbRec.received.includes(id) });
        } else {
            taskList.push({ type, id, count: 0, received: false });
        }
    }
    return { point, taskList, box }
}

export async function getPvpTask(roleId: string) {
    let type = TASK_FUN_TYPE.PVP;
    let recMap = await UserTaskRecModel.findByRoleAndType(roleId, type); // group=>userTaskRec

    let taskList: TaskListReturn[] = [];
    for (let [id, dic] of gameData.pvpDailyTask) {
        let dbRec = recMap.get(dic.taskType)?.get(dic.group);
        if (dbRec) {
            taskList.push({ type, id, count: dbRec.count, received: dbRec.received.includes(id) });
        } else {
            taskList.push({ type, id, count: 0, received: false });
        }
    }
    return { taskList }
}

// 刷新每日任务
export async function refDailyTask(roleId: string, sid: string) {
    let userTask = await UserTaskModel.findByRole(roleId);
    let taskList = await getDailyTask(roleId, userTask);

    // 转移每日任务
    await removeHistoryTask(roleId, TASK_FUN_TYPE.DAILY);

    let uids = [{ uid: roleId, sid }];
    pinus.app.get('channelService').pushMessageByUids('onDailyTaskRefresh', resResult(STATUS.SUCCESS, { taskList }), uids);

}

export async function removeHistoryTask(roleId: string, type: number, today?: Date) {

    // 转移每日任务
    let history = await UserTaskRecModel.getHistoryRec(roleId, type, today);
    if (history.length > 0) {
        await UserTaskHistoryModel.pushUserTask(roleId, history);
        await UserTaskRecModel.deleteHistory(history);
    }
}

// 刷新每日宝箱数量
export async function refDailyTaskBox(roleId: string, sid: string, debug = false) {
    let userTask = await UserTaskModel.refreshWeekly(roleId, debug);
    if (userTask) {
        let { dailyTaskPoint: point, dailyTaskPointWeekly: weeklyPoint, dailyTaskBox: box } = userTask;
        let uids = [{ uid: roleId, sid }];
        pinus.app.get('channelService').pushMessageByUids('onTaskBoxRefresh', resResult(STATUS.SUCCESS, {
            type: TASK_FUN_TYPE.DAILY,
            point, weeklyPoint, box
        }), uids);
    }
}

//任务条件
//英雄满装备且都镶嵌相同阶数的宝石
export async function checkTaskConditionEquipSuitJewelStage(hero: HeroType) {
    let isTask = true;//是否满足任务条件
    let jewelLevel = -1;//宝石阶数
    for (let i = 0; i < hero.ePlace.length; i++) {
        let equipObj = <EquipType>hero.ePlace[i].equip;
        if (equipObj) {
            let equipObjInfo = getGoodById(equipObj.id);
            if (equipObj.holes.length == equipObjInfo.hole && equipObjInfo.hole > 0) {
                for (let j = 0; j < equipObj.holes.length; j++) {
                    let jewel = equipObj.holes[j].jewel;
                    let jewelInfo = getGoodById(jewel);
                    if (jewelInfo) {
                        if (jewelLevel == -1) {
                            jewelLevel = jewelInfo.lvLimited;
                        } else if (jewelInfo.lvLimited != jewelLevel) {
                            //宝石阶数不同
                            isTask = false;
                            break;
                        }
                    }
                }
            } else {
                //宝石没有镶满
                isTask = false;
                break;
            }
        }
    }
    return { isTask, jewelLevel };
}