import { ITID, CONSUME_TYPE, getCurNameById, ITEM_TABLE, HERO_SYSTEM_TYPE, CURRENCY_BY_TYPE, FIGURE_UNLOCK_CONDITION, REDIS_KEY, TASK_TYPE } from './../consts';
import { EquipModel } from './../db/Equip';
import { resResult } from '../pubUtils/util';
import { RoleModel, RoleType } from '../db/Role';
import { setAp } from './actionPointService';
import { calAllHeroCe, pushCalPlayerCe, pushCalAllHeroCe } from './playerCeService';
import { ItemModel } from '../db/Item';
import { STATUS } from '../consts/statusCode';
import { pinus } from 'pinus';
import { addEquips, addBags, addSkin, addFigure, unlockFigure as pubUnlockFigure, createHeroes as pubCreateHeroes, transPiece } from '../pubUtils/itemUtils';
import { EquipInter, ItemInter, BagInter } from '../pubUtils/interface';
import { gameData } from '../pubUtils/data';
import { uniq, indexOf, findIndex } from 'underscore';
import { HeroModel, HeroType } from '../db/Hero';
import { Figure } from '../domain/dbGeneral';
import { Rank } from './rankService';
import { checkActivityTask, pushActivityUpdate, pushTaskUpdate } from './taskService';
import { CreateHeroParam } from '../domain/roleField/hero';
import { HeroSkin } from '../db/Hero';

export async function handleCost(roleId: string, sid: string, goods: Array<ItemInter>) {
    let currencysMap: any = {};
    let equips: Array<number> = [];
    let bags: Array<{ id: number, count: number }> = [];
    let uids = [{ uid: roleId, sid }];
    if (!sortConsumes(goods, bags, currencysMap, equips))
        return false;
    // 检查货币是否充足
    if (!!Object.keys(currencysMap).length) {
        let role = await RoleModel.findByRoleId(roleId);
        for (let key in currencysMap) {
            currencysMap[key] = role[key] - currencysMap[key];
            if (currencysMap[key] < 0) {
                return false;
            }
        }
    }
    //检查装备是否存在
    if (!!equips.length) {
        let resEquips = await EquipModel.getEquips(equips);
        if (resEquips.length < equips.length)
            return false;
    }
    //检查并修改道具
    if (bags.length > 0) {
        let { hasError, result } = await ItemModel.decreaseItems(roleId, bags);
        if (hasError) return false;
        pinus.app.get('channelService').pushMessageByUids('onItemUpdate', resResult(STATUS.SUCCESS, { goods: result }), uids);
    }

    //删除装备
    if (!!equips.length) {
        await EquipModel.deleteEquips(equips);
        pinus.app.get('channelService').pushMessageByUids('onEquipDel', resResult(STATUS.SUCCESS, { equips }), uids);
    }

    //消耗玩家货币
    if (!!Object.keys(currencysMap).length) {
        await RoleModel.updateRoleInfo(roleId, currencysMap);
        pinus.app.get('channelService').pushMessageByUids('onPlayerDataChange', resResult(STATUS.SUCCESS, currencysMap), uids);
    }

    return true;
}

function sortConsumes(goods: Array<ItemInter>, bags: Array<ItemInter>, currencysMap: any, equips: Array<number>) {
    for (let good of goods) {
        if (good.count == 0) continue;
        let goodInfo = gameData.goods.get(good.id);
        let { type, table } = ITID.get(goodInfo.itid);

        if (table == ITEM_TABLE.EQUIP) {
            if (!!good.seqId) {
                equips.push(good.seqId);
            } else {
                return false;
            }
        } else if (table == ITEM_TABLE.ITEM) {
            let index = indexOf(bags, { id: good.id });
            if (index > 0) {
                bags[index].count = bags[index].count + good.count;
            } else {
                bags.push(good);
            }
        } else if (table == ITEM_TABLE.SKIN) {
            return false
        } else if (table == ITEM_TABLE.ROLE) {
            let curname = getCurNameById(goodInfo.good_id);
            if (!!curname) {
                if (curname != 'ap') {
                    currencysMap[curname] = (currencysMap[curname] || 0) + good.count;
                } else {
                    return false;
                }
            }
        }
    }
    return true;
}

// TODO: sid 在方法内部获取，且不一定存在
export async function addItems(roleId: string, roleName: string, sid: string, goods: Array<ItemInter>) {
    let showItems: Array<ItemInter> = [];
    let currencysMap: any = {};
    let equips: Array<EquipInter> = [];
    let bags: Array<BagInter> = [];
    let skins: Array<number> = [];
    let figures: Array<number> = [];
    let uids = [{ uid: roleId, sid }];
    sortItems(goods, bags, skins, figures, currencysMap, equips, showItems);
    let equipInfos = [], taskPushMessage = [];
    for (let equip of equips) {
        let { equipInfo, pushMessage } = await addEquips(roleId, roleName, equip);
        showItems.push({ seqId: equipInfo.seqId, id: equip.id, count: 1 });
        equipInfos.push(equipInfo);
        taskPushMessage.concat(pushMessage);
    }
    //装备推送
    if (!!equipInfos.length)
        pinus.app.get('channelService').pushMessageByUids('onEquipAdd', resResult(STATUS.SUCCESS, { equipInfos }), uids);

    pushTaskUpdate(roleId, sid, null, taskPushMessage);

    //统计装备
    if (equipInfos.length > 0) {
        let { serverId } = await RoleModel.findByRoleId(roleId);
        await checkActivityTask(serverId, sid, [], roleId, TASK_TYPE.EQUIP_QUALITY_COUNT, equipInfos.length, { equips: equipInfos.map(obj => { return { quality: obj.quality } }) })
    }

    //货币推送
    if (!!Object.keys(currencysMap).length) {
        let role = await RoleModel.findByRoleId(roleId);
        for (let key in currencysMap) {
            if (key == 'ap') {
                let { ap } = await setAp(roleId, role.lv, currencysMap[key], sid, []);
                currencysMap.ap = ap;
            } else {
                currencysMap[key] += role[key];
            }
        }
        await RoleModel.updateRoleInfo(roleId, currencysMap);
        pinus.app.get('channelService').pushMessageByUids('onPlayerDataChange', resResult(STATUS.SUCCESS, currencysMap), uids);
    }

    let bagInfos = [];
    for (let item of bags) {
        let bagInfo = await addBags(roleId, roleName, item);
        showItems.push({ id: item.id, count: item.count });
        bagInfos.push(bagInfo);
    }
    //背包除去装备推送 
    if (!!bagInfos.length)
        pinus.app.get('channelService').pushMessageByUids('onItemUpdate', resResult(STATUS.SUCCESS, { goods: bagInfos }), uids);


    let heroskins: {skins: HeroSkin[], hid: number}[] = []; // 皮肤推送信息
    let skinInfos: {id: number, hid: number }[] = [];
    let figureInfos:{ heads: Figure[], frames: Figure[], spines: Figure[] }[] = []; // 头像变化推送信息
    let calAllHeroResult = undefined; // 全局战力变化推送

    for (let skinId of skins) {//皮肤推送
        let result = await addSkin(roleId, roleName, skinId, false);
        console.log(result)
        if (!!result) {
            showItems.push({ id: skinId, count: 1 });
            figureInfos.push(result.figureInfo);
            if(result.hero) {
                heroskins.push({ skins: result.hero.skins, hid: result.hero.hid });
                if(result.calAllHeroResult) calAllHeroResult = result.calAllHeroResult;
            }
            skinInfos.push({ id: skinId, hid: result.hero?.hid||0 })
        }
    }
    if (!!skinInfos.length) {
        pushHeroSkinMsg(heroskins, skinInfos, uids);  // 推送onHeroSkinChange
    }
    // 推送全局加成信息
    if(calAllHeroResult) await pushCalAllHeroCe(roleId, sid, calAllHeroResult);

    // 获得头像和相框等
    if(!!figures && figures.length > 0) {
        let figureInfo = await addFigure(roleId, figures);
        if(figureInfo) figureInfos.push(figureInfo);
        for (let id of figures) {//皮肤推送        
            showItems.push({ id, count: 1 });
        }
    }

    // 获得头像或相框或形象推送
    if(!!figureInfos && figureInfos.length > 0) {
        for(let figureInfo of figureInfos) {
            pinus.app.get('channelService').pushMessageByUids('onHeadChange', resResult(STATUS.SUCCESS, { ...figureInfo }), uids);
        }
    }

    return showItems;
}

function sortItems(goods: Array<ItemInter>, bags: Array<BagInter>, skins: Array<number>, figures: Array<number>, currencysMap: any, equips: Array<EquipInter>, showItems: Array<ItemInter>) {
    for (let good of goods) {
        let goodInfo = gameData.goods.get(good.id);
        // 道具不存在时先跳过
        if (!goodInfo) {
            console.log('sortItems 道具不存在:', good.id);
            continue;
        }

        let { type, table, isCurrency } = ITID.get(goodInfo.itid);
        if (table == ITEM_TABLE.EQUIP) {
            for (let i = 0; i < good.count; i++) {
                equips.push({ id: good.id, ...goodInfo });
            }
        } else if (table == ITEM_TABLE.ITEM) {

            let index = findIndex(bags, { id: good.id });
            if (index > 0) {
                bags[index].count = bags[index].count + good.count;
            } else {
                bags.push({ id: good.id, count: good.count, itemName: goodInfo.name, hid: goodInfo.hid || 0, type });
            }

        } else if (table == ITEM_TABLE.SKIN) {
            if (type == CONSUME_TYPE.SKIN) {
                let index = indexOf(skins, good.id);
                if (index == -1) {
                    skins.push(good.id);
                }
            }
        } else if (table == ITEM_TABLE.ROLE) {

            if (!!isCurrency) {
                let curname = getCurNameById(goodInfo.good_id);
                if (!!curname) {
                    let index = findIndex(showItems, { id: good.id });
                    if (index > 0) {
                        showItems[index].count = showItems[index].count + good.count;
                    } else {
                        showItems.push(good);
                    }
                    currencysMap[curname] = (currencysMap[curname] || 0) + good.count;
                }
            } else {
                if (type == CONSUME_TYPE.HEAD || type == CONSUME_TYPE.FRAME || type == CONSUME_TYPE.SPINE) {
                    let index = indexOf(figures, good.id);
                    if (index == -1) {
                        figures.push(good.id);
                    }
                }
            }
        }
    }
}

export async function decreaseItems(roleId: string, sid: string, bags: Array<{ id: number, count: number, ratio?: number }>) {
    let uids = [{ uid: roleId, sid }];
    if (bags.length > 0) {
        let { hasError, result } = await ItemModel.decreaseItems(roleId, bags);
        if (hasError) return true;
        pinus.app.get('channelService').pushMessageByUids('onItemUpdate', resResult(STATUS.SUCCESS, { goods: result }), uids);
    }
    return false;
}


export async function checkGoods(roleId: string, goodIds: Array<number>) {
    let equipIds: Array<number> = [];
    let itemIds: Array<number> = [];
    let hids: Array<number> = [];
    goodIds = uniq(goodIds);
    for (let goodId of goodIds) {
        let goodInfo = gameData.goods.get(goodId);
        if (!!goodInfo) {
            let { table } = ITID.get(goodInfo.itid);
            if (table == ITEM_TABLE.EQUIP) {
                equipIds.push(goodId);
            } else if (table == ITEM_TABLE.ITEM) {
                itemIds.push(goodId);
            }
        } else {
            hids.push(goodId);
        }
    }

    if (!!hids.length) {
        let heros = await HeroModel.findByHidRange(hids, roleId);
        if (heros.length < hids.length)
            return false;
    }

    //检查装备是否存在
    if (!!equipIds.length) {
        let resEquips = await EquipModel.getEquipsByIds(roleId, equipIds);
        resEquips = uniq(resEquips, function (resEquip) {
            return resEquip.id;
        });
        if (resEquips.length < equipIds.length)
            return false;
    }
    //检查并修改道具
    if (itemIds.length > 0) {
        let items = await ItemModel.findbyRoleAndIds(roleId, itemIds);
        if (items.length < itemIds.length)
            return false;
    }
    return true;
}


export async function unlockFigure(sid: string, roleId: string, conditions: { type: number, paramHid?: number, paramFavourLv?: number, paramSkinId?: number }[], role?: RoleType) {
    let figureInfo = await pubUnlockFigure(roleId, conditions, role);
    await pushFigureUpdate(roleId, sid, figureInfo);
}

export async function pushFigureUpdate(roleId: string, sid: string, figureInfo: { heads: Figure[], frames: Figure[], spines: Figure[] }) {
    if (!!figureInfo && (figureInfo.heads.length > 0 || figureInfo.frames.length > 0 || figureInfo.spines.length > 0)) {
        let uids = [{ uid: roleId, sid }];
        pinus.app.get('channelService').pushMessageByUids('onHeadChange', resResult(STATUS.SUCCESS, { ...figureInfo }), uids);
    }
}

/**
 * 创建多个武将
 * @param roleId 
 * @param sid 
 * @param serverId 
 * @param heroInfo 
 */
export async function createHeroes(roleId: string, roleName: string, sid: string, serverId: number, funcs: number[], heroInfo: CreateHeroParam[]) {
    let hids = heroInfo.map(cur => cur.hid);
    let userHeroesMap = await HeroModel.findMapByHidRange(hids, roleId);


    let newHeroInfo: CreateHeroParam[] = [], pieces: ItemInter[] = [];
    for (let h of heroInfo) {
        let heroCount = h.count || 1;
        if (userHeroesMap.has(h.hid)) {
            let { pieceId, count } = transPiece(h.hid);
            pieces.push({ id: pieceId, count: count * heroCount });
        } else {
            newHeroInfo.push(h)
            userHeroesMap.set(h.hid, null);
            if (heroCount > 1) {
                let { pieceId, count } = transPiece(h.hid);
                pieces.push({ id: pieceId, count: count * (heroCount - 1) });
            }
        }
    }

    let resultHeroes: HeroType[] = [], resultItems: ItemInter[] = [];
    if (newHeroInfo.length > 0) {

        let { heroes, role, figureInfo, calHeroResults, calAllHeroResult, taskPushMessage, activityTaskPushMessage } = await pubCreateHeroes(roleId, roleName, serverId, newHeroInfo, funcs);

        let r = new Rank(REDIS_KEY.HERO_NUM_RANK, { serverId });
        await r.setRankWithRoleInfo(roleId, role.heroNum, role.heroNumUpdatedAt, role);

        await pushFigureUpdate(roleId, sid, figureInfo);

        for (let calHeroResult of calHeroResults) {
            await pushCalPlayerCe(roleId, sid, calHeroResult);
        }
        await pushCalAllHeroCe(roleId, sid, calAllHeroResult);

        pushTaskUpdate(roleId, sid, null, taskPushMessage);
        pushActivityUpdate(roleId, sid, null, activityTaskPushMessage);
        resultHeroes = heroes;
    }

    if (pieces.length > 0) {
        let goods = await addItems(roleId, roleName, sid, pieces);
        resultItems = goods;
    }
    return { heroes: resultHeroes, goods: resultItems }
}

export async function createHero(roleId: string, roleName: string, sid: string, serverId: number, funcs: number[], heroInfo: CreateHeroParam) {
    let result = await createHeroes(roleId, roleName, sid, serverId, funcs, [heroInfo]);
    return result;
}

/**
 * 皮肤数据变化去重、推送
 * @param heroskins 推送的皮肤
 * @param uids 玩家
 */
function pushHeroSkinMsg(heroskins: {skins: HeroSkin[], hid: number}[],  skinInfos: {id: number, hid: number }[], uids: {uid: string, sid: string}[]) {
    let pushSkinInfos: {skins: HeroSkin[], hid: number}[] = []; // 可能会有重复的
    for(let { skins, hid } of heroskins) {
        let index = pushSkinInfos.findIndex(cur => cur.hid == hid);
        if(index == -1) {
            pushSkinInfos.push({skins, hid});
        } else {
            if(skins.length > pushSkinInfos[index].skins.length) {
                pushSkinInfos[index] = {skins, hid};
            }
        }
    }
    if(pushSkinInfos.length > 0 || skinInfos.length > 0) {
        pinus.app.get('channelService').pushMessageByUids('onHeroSkinChange', resResult(STATUS.SUCCESS, { heros: heroskins, skins: skinInfos }), uids);
    }
}