import { mergeSameGoods, deepCopy } from '../pubUtils/util';
import { EquipModel } from "../db/Equip";
import { HeroModel, EPlace, HeroType } from "../db/Hero";
import { getHeroJob, getGoodById, gameData, getJewelById, getHeroEquipByClassId } from "../pubUtils/data";
import { calPlayerCeAndSave } from "./playerCeService";
import { HERO_SYSTEM_TYPE, TASK_TYPE } from "../consts";
import { EquipType } from "../db/Equip";
import { calEquipSeids } from '../pubUtils/playerCe';
import { indexOf, findIndex } from 'underscore';
import { checkTask, checkTaskWithHero, checkTaskWithEquip, checkActivityTask } from './taskService';
/**
 * 校验前端传入的消耗数量是否准确，并返回消耗的道具并加上特殊材料needConsumes
 * @param consumes 
 * @param jewel 
 * @param jewelCount 
 */
export function checkMaterialEnough(consumes: Array<{ id: number, count: number }>, jewel: number, jewelCount: number) {
    let comJewelMap = {};
    consumes = mergeSameGoods(consumes);
    let needConsumes: Array<{ id: number, count: number }> = [];
    let gidJewelInfo = getGoodById(jewel);//目标宝石信息
    for (let { id, count } of consumes) {
        let jewelInfo = getJewelById(id);
        if (!jewelInfo || !jewelInfo.count) //筛选出特殊材料，特殊材料没有合成下一级需要的count数量
            continue;
        needConsumes.push({ id, count });//将该宝石加入消耗中
        comJewelMap[id] = count + (comJewelMap[id] || 0);
        for (let i = jewelInfo.lvLimited; i < gidJewelInfo.lvLimited; i++) {//当前消耗的宝石升级到目标宝石的消耗
            if (((comJewelMap[id] || 0) % jewelInfo.count != 0)) {//jewelInfo的count，表示宝石id合成下一级需要的数量
                break;//数量有余，跳出循环，等待下次合成
            }
            let comcount = Math.floor(((comJewelMap[id] || 0)) / jewelInfo.count);
            if (comcount < 1) {
                break;//不能合成，跳出循环，等待下次合成
            }
            comJewelMap[jewelInfo.nextJewelId] = comcount + (comJewelMap[jewelInfo.nextJewelId] || 0);//jewelInfo的nextJewelId，表示宝石id合成下一级的宝石good_id
            delete comJewelMap[id];
            if (!!jewelInfo.specialCount)
                needConsumes.push({ count: jewelInfo.specialCount * comcount, id: jewelInfo.nextSpecialId });//消耗中曾加合成下一级需要的特殊消耗物品的数量
            id = jewelInfo.nextJewelId;

            jewelInfo = getJewelById(jewelInfo.nextJewelId);
        }
    }
    if (comJewelMap[jewel] != jewelCount || Object.keys(comJewelMap).length != 1)//检查最终是否可以合成目标宝石jewel，以及对应的数量jewelCount
        return false;
    return needConsumes;
}
/**
 * 将装备卸载下来，并检查是否有替换装备的武将，若有则替换
 * 武将A（装备A）&武将B（装备B） ==> 武将A（装备B）&武将B（装备A）
 * 武将A（装备A）& 装备B ==> 武将A（装备B）& 装备A
 * @param roleId 玩家id
 * @param sid 
 * @param equip 目标武将要卸下的装备，装备A
 * @param hid 要装上的装备备原来装备着的武将id， 武将B
 * @param id 装备类型
 * @param seqId 要装上的装备的唯一id 装备B
 */
export async function changeEquip(serverId: number, roleId: string, sid: string, equipA: EquipType, hid: number, id: number, equipB: EquipType, funcs: number[]) {
    let heroB: HeroType;
    if (!!hid) //需要卸下或者替换的武将
        heroB = await HeroModel.findByHidAndRoleWithEquip(hid, roleId);//需要替换的武将

    if (!!equipA) {//需要卸下的装备
        if (!!heroB) {
            let goodInfo = getGoodById(equipA.id);
            if (goodInfo.lvLimited > heroB.lv) {
                let res = await takeOffEquipAndCalPlayerCe(roleId, sid, heroB, equipB, id, funcs);//卸下装备并重算战力
                return res;
            }
            let { jobid } = gameData.hero.get(hid);
            let { job_class } = getHeroJob(jobid);
            let { classId } = getHeroEquipByClassId(goodInfo.itid);
            if (indexOf(classId, job_class) < 0) {
                let res = await takeOffEquipAndCalPlayerCe(roleId, sid, heroB, equipB, id, funcs);//卸下装备并重算战力
                return res;
            }
            let res = await dressEquip(serverId, roleId, sid, heroB, equipA, funcs);//替换给武将，并计算战力
            return res;
        } else {
            let res = await takeOffEquipAndCalPlayerCe(roleId, sid, null, equipA, id, funcs);//卸下装备并重算战力
            return res;
        }
    } else if (!!heroB) {//从穿戴装备的武将上卸下装备
        let res = await takeOffEquipAndCalPlayerCe(roleId, sid, heroB, equipB, id, funcs);//卸下装备并重算战力
        return res
    }
}
/**
 * 从穿戴装备的武将上卸下装备,并重算战力
 * @param roleId 
 * @param sid 
 * @param seqId 
 * @param hero 
 * @param id 
 */
export async function takeOffEquipAndCalPlayerCe(roleId: string, sid: string, hero: HeroType, equip: EquipType, id: number, funcs: number[]) {
    console.log(roleId, sid, hero, equip, id)
    if (hero) {
        let args = calEquipSeids(hero);
        hero = await HeroModel.removeEquip(roleId, hero.hid, id, equip._id);

        await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, sid, roleId, hero, {}, args);
        await checkTaskWithHero(roleId, sid, funcs, TASK_TYPE.EQUIP_BY_HERO, hero, [-1]);
    } else {
        await EquipModel.putOnOrOff(equip._id, 0);
    }
    // 任务
    await checkTask(roleId, sid, funcs, TASK_TYPE.EQUIP_SUM, -1, true, {});
    await checkTaskWithEquip(roleId, sid, funcs, TASK_TYPE.EQUIP_QUALITY, equip, [-1]);
    return { seqId: equip.seqId, hid: 0 };
}
/**
 * 穿戴装备并重算战力
 * @param roleId 
 * @param sid 
 * @param hero 
 * @param equip 
 */
export async function dressEquip(serverId: number, roleId: string, sid: string, hero: HeroType, equip: EquipType, funcs: number[]) {
    let args = calEquipSeids(hero);

    hero = await HeroModel.addEquip(roleId, hero.hid, equip.ePlaceId, equip._id);
    await calPlayerCeAndSave(HERO_SYSTEM_TYPE.EQUIP, sid, roleId, hero, {}, args);

    // 任务
    await checkTask(roleId, sid, funcs, TASK_TYPE.EQUIP_SUM, 1, true, {});
    await checkTaskWithHero(roleId, sid, funcs, TASK_TYPE.EQUIP_BY_HERO, hero, [1]);
    await checkTaskWithEquip(roleId, sid, funcs, TASK_TYPE.EQUIP_QUALITY, equip, [1]);
    await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.EQUIP_QUALITY, 1, { quality: equip.quality })
    await checkActivityTask(serverId, sid, funcs, roleId, TASK_TYPE.EQUIP_SUM, 1)

    return { seqId: equip.seqId, hid: hero.hid };
}