import { mergeSameGoods, getRandEelm, getRandValueByMinMax } from '../pubUtils/util';
import { EquipModel, RandMain, RandSe } from "../db/Equip";
import { HeroModel, HeroType } from "../db/Hero";
import { getGoodById, gameData, getJewelById, getQuenchGradeByValue, getQuenchConsume, getQuenchByQualityAndGrade } from "../pubUtils/data";
import { calPlayerCeAndSave } from "./playerCeService";
import { CONSUME_TYPE, HERO_SYSTEM_TYPE, ITID, TASK_TYPE } from "../consts";
import { dicGoods, DicGoods } from '../pubUtils/dictionary/DicGoods';
import { QuenchLogParam } from '../domain/roleField/equip';
import { QUENCH } from '../pubUtils/dicParam';
import { DicQuenchQuality } from '../pubUtils/dictionary/DicQuenchQuality';

/**
 * 校验前端传入的消耗数量是否准确，并返回消耗的道具并加上特殊材料needConsumes
 * @param consumes 
 * @param jewel 
 * @param jewelCount 
 */
export function checkMaterialEnough(consumes: Array<{ id: number, count: number }>, jewel: number, jewelCount: number) {
    let comJewelMap = new Map<number, number>(); // good_id => count
    let needConsumes:{ id: number, count: number, ratio?: number }[] = []
    for(let {id, count} of consumes) {
        if(!comJewelMap.has(id)) {
            comJewelMap.set(id, count);
        } else {
            comJewelMap.set(id, comJewelMap.get(id) + count);
        }
    }

    function checkCurMeterial(target: number, targetCount: number) {
        let dic = getGoodById(target);
        if(!dic) return false;
        let { composeMaterial } = dic;

        let isEnough = true;
        for(let { id, count } of composeMaterial) {
            let consumeCount = comJewelMap.get(id)||0;
            let dicGood = getGoodById(id);
            if(!dicGoods) { isEnough = false; break; }
            let dicItid = ITID.get(dicGood.itid);
            if(dicItid.type != CONSUME_TYPE.JEWEL) {
                if(consumeCount < count * targetCount) {
                    isEnough = false; break;
                } else {
                    comJewelMap.set(id, consumeCount - count * targetCount);
                    needConsumes.push({ id, count: count * targetCount });
                }
            } else {
                if(consumeCount < count * targetCount) {
                    comJewelMap.set(id, 0);
                    needConsumes.push({ id, count: consumeCount });
                    isEnough = checkCurMeterial(id, count * targetCount - consumeCount);
                } else {
                    comJewelMap.set(id, consumeCount - count * targetCount);
                    needConsumes.push({ id, count: count * targetCount });
                }

            }
        }
        return isEnough
    }

    let isEnough = checkCurMeterial(jewel, jewelCount);
    return isEnough? needConsumes: false;
}

export function checkEquipCanPut(hero: HeroType, id: number) {
    let hid = hero.skinId;
    let dicGood = gameData.goods.get(id);
    if(dicGood.lvLimited > hero.lv) return false;
    let dicHero = gameData.hero.get(hid);
    if(dicGood.jobLimited.indexOf(0) == -1 && dicGood.jobLimited.indexOf(dicHero.jobClass) == -1) return false;
    if(dicGood.charLimited.indexOf(0) == -1 && dicGood.charLimited.indexOf(hid) == -1) return false;
    return true 
}


/**
 * 淬火一次
 * @param roleId 玩家id
 * @param sid 玩家sid
 * @param randMain 装备上的属性随机值
 * @param dicQuench 淬火表
 * @param dicGoods 物品表
 * @returns 
 */
export async function quenchOnce(randMain: RandMain[], dicQuench: DicQuenchQuality, dicGoods: DicGoods) {
    let { quality, equipLvl } = dicGoods;
    
    let canRandMain = randMain.filter(cur => { // 已升满的属性就不再淬火了
        return cur.rand < dicQuench.singleRatioMax;
    });
    let randMainResult = getRandEelm(canRandMain);
    if(randMainResult.length == 0) return false;

    let add = new Map<number, number>(); // id => value，增加的数量
    let isCriticle = Math.random() * 100 < dicQuench.critProbability; // 暴击
    let addAttr = isCriticle? dicQuench.critEffect * QUENCH.QUENCH_UNIT_UPRATIO: QUENCH.QUENCH_UNIT_UPRATIO;
    let overAttr = randMainResult[0].rand + addAttr - dicQuench.singleRatioMax; // 如果有暴击，超出当前品相上限时
    if(overAttr > 0) { // 超出，转到另一条属性
        let anotherRandMain = canRandMain.filter(cur => {
            return cur.id != randMainResult[0].id;
        });
        if(anotherRandMain.length > 0) {
            let anotherOverAttr = anotherRandMain[0].rand + overAttr - dicQuench.singleRatioMax;
            if(anotherOverAttr > 0) {
                add.set(anotherRandMain[0].id, overAttr - anotherOverAttr);
            } else {
                add.set(anotherRandMain[0].id, overAttr);
            }
        }
        add.set(randMainResult[0].id, addAttr - overAttr);
    } else {
        add.set(randMainResult[0].id, addAttr);
    }

    let value = 0;
    for(let r of randMain) {
        if(add.has(r.id)) {
            r.rand += add.get(r.id);
        }
        value += r.rand;
    }
    let grade = getQuenchGradeByValue(quality, value/2);
    
    // 消耗
    let consumes = getQuenchConsume(equipLvl, quality);

    let log = new QuenchLogParam(isCriticle, add);
    return { randMain, grade, log, consumes };
}

/**
 * 检查该品相是否到顶
 * @param quality 品质
 * @param grade 品相
 * @param randMain 装备上的随机值
 * @returns 
 */
export function checkQuenchMaxByQualityAndGrade(quality: number, grade: number, randMain: RandMain[]) {
    let isMax = true;
    let dic = getQuenchByQualityAndGrade(quality, grade);
    if(!dic) return true;
    for(let { rand } of randMain) {
        if(rand < dic.max) isMax = false;
    }
    return isMax;
}

export function getRandSeResult(id: number, randSe: RandSe[]) {
    let dicGoods = gameData.goods.get(id);
    if (!dicGoods) return false;

    let { randomEffect } = dicGoods; // 配置的可随机seid
    let chosen = randSe.filter(cur => cur.locked).map(cur => cur.seid); // 上一轮随机出来的
    let randomResult: number[] = getRandEelm(randomEffect.filter(cur => !chosen.includes(cur)), randSe.length); // 随机出的结果

    for (let i = 0; i < randSe.length; i++) {
        if (!randSe[i].locked) {
            let random = gameData.randomEffectPool.get(randomResult[i]);
            if (!random) break;
            let rand = 0;
            if (random.id > 0) rand = getRandValueByMinMax(random.Min, random.Max, 0);
            randSe[i].seid = random.id;
            randSe[i].rand = rand;
        }
    }
    return randSe
}

export async function refineOnce(lv: number, refineLv: number) {

    let dicRefine = gameData.refine.get(refineLv + 1);
    if (!dicRefine) return false;

    if(lv < dicRefine.levelLimited) return false;

    return {
        refineLv: refineLv + 1,
        consumes: dicRefine.consume
    }
}

export function checkRefineReachNextLv(oldRefineLv: number, refineLv: number) {
    let oldDic = gameData.refine.get(oldRefineLv);
    let dic = gameData.refine.get(refineLv);
    if(!oldDic || !dic) return true;

    return dic.level > oldDic.level;
}

export function calEquipCe(goodsAbility: Map<number, number>, randMain: RandMain[]) {
    let ce = 0;
    for(let [ id, ratio ] of gameData.equipAttributeRatio) {
        let valueBase = goodsAbility.get(id);
        let curRand = randMain.find(cur => cur.id == id);
        let valueRand = curRand?curRand.rand: 0;
        ce += Math.floor(valueBase * valueRand * ratio / 100);
    }
    return ce
}