import { Subject } from "rxjs";
import { first, map } from "rxjs/operators";
import { environment } from "../../../../../environments/environment";
import { ADButtons, ADIcon } from "../../../../ui/alert-dlg/alert-dlg.model";
import { MD2Logic } from "../../massive-darkness2.logic";
import { AttackInfo, AttackTarget, IMobFactory, MD2Icon, MobInfo, MobType, TreasureItem, TreasureType } from "../../massive-darkness2.model";
import { MobSkillType } from "../../massive-darkness2.model.boss";
import { MD2DiceSet, MD2MobSkill } from "../../massive-darkness2.db.model";

const MD2_IMG_URL = (id: string = null) => { return `${environment.apiUrl}/Files/Images/MD2/Mobs${(id ? `${encodeURI(id)}` : '')}` }

export abstract class CoreGameRMFactory implements IMobFactory {
    abstract mobName: string;
    abstract generate(level: number): MobInfo
    protected mob: MobInfo;
    protected loadLevelInfo(mobName: string, level: number) {
        let levelInfo = CORE_GAME_MOB_LEVEL.find(m => m.name == mobName && level >= m.level);

        this.mob = new MobInfo({
            type: MobType.RoamingMonster,
            name: mobName, hpPerHero: levelInfo.hp, level: level, rewardTokens: levelInfo.rewardTokens,
            attackInfos: levelInfo.attackInfos,
            defenseInfo: levelInfo.defenseInfo,
            actionSubject: new Subject<string>()
        });
        this.mob.leaderImgUrl = MD2_IMG_URL(`/CoreGame/RoamingMonsters/${this.mob.name}/Stand.png`);
        //this.mob.minionImgUrl = MD2_IMG_URL(`CoreGame/Mobs/${encodeURI(this.mob.name)}/Minion.png`);


        if (level < 3) {
            this.mob.rewardTokens = 2;
            this.mob.fixedCarriedTreasure = [new TreasureItem(TreasureType.Rare)];
        } else if (level < 5) {
            this.mob.rewardTokens = 2;
            this.mob.fixedCarriedTreasure = [new TreasureItem(TreasureType.Epic)];
        } else {
            this.mob.rewardTokens = 0;
            this.mob.fixedCarriedTreasure = [new TreasureItem(TreasureType.Epic, 3)];
        }

    }
    iconHtml(icon: MD2Icon, cssClass = '') {
        if (icon == MD2Icon.Fire) {
            cssClass += ' g-color-google-plus ';
        }
        if (icon == MD2Icon.Frost || icon == MD2Icon.Mana) {
            cssClass += ' g-color-aqua ';
        }

        if (icon < MD2Icon.RedDice) {
            return `<span class='MD2Icon ${cssClass}'>${String.fromCharCode(65 + icon)}</span>`

        }
        else {
            return `<span class='MD2Icon  dice ${MD2Icon[icon].replace('Dice', '')} ${cssClass}'></span>`;
        }
    }
}
export class RMUndeadQueenFactory extends CoreGameRMFactory {
    mobName: string = 'Ytheria, Undead Queen';
    generate(level: number): MobInfo {
        this.loadLevelInfo('Ytheria, Undead Queen', level);

        this.mob.activateFunction = (mob, msgBoxService, heros) => {
            let actionResult = '';

            msgBoxService.show('Is There more than 1 Hero in LoS of Undead Queen?', {
                icon: ADIcon.QUESTION,
                buttons: ADButtons.YesNo
            }).pipe(first()).subscribe(result => {
                if (result) {
                    mob.actions = 0;
                    mob.actionSubject.next(
                        `Undead Queen attacks each Hero in LoS(resolve each attack separately).`
                    );
                } else {
                    msgBoxService.show('Is There any Hero in LoS of Undead Queen?', {
                        icon: ADIcon.QUESTION,
                        buttons: ADButtons.YesNo
                    }).pipe(first()).subscribe(result => {
                        if (result) {
                            if (level < 3) {
                                actionResult = `Undead Queen +1 ${this.iconHtml(MD2Icon.YellowDice)} when attack`;
                            } else if (level < 5) {
                                actionResult = `Undead Queen +1 ${this.iconHtml(MD2Icon.YellowDice)} 1 ${this.iconHtml(MD2Icon.OrangeDice)} when attack`;
                            } else {
                                actionResult = `Undead Queen +2 ${this.iconHtml(MD2Icon.OrangeDice)} when attack`;
                            }
                            mob.actions = 0;
                            mob.actionSubject.next(
                                actionResult
                            );
                        } else {

                            mob.actions = 2;
                            mob.actionSubject.next(
                                `Undead Queen Gains 2 Actions`
                            );
                        }
                    });
                }
            });
        }

        this.mob.skills = [
            {
                description: `Add 1 Minion to each Mob in the Dungeon, if possible.`,
                type: MobSkillType.Attack,

                skillRoll: 1
            } as MD2MobSkill];
        return this.mob;
    }
}
export class RMAndraFactory extends CoreGameRMFactory {
    mobName: string = 'Andra';
    generate(level: number): MobInfo {
        this.loadLevelInfo('Andra', level);
        let damage = 2;

        if (level < 3) {
            damage = 1;
        }

        this.mob.activateFunction = (mob, msgBoxService, heros) => {
            let actionResult = '';

            mob.actions = 0;
            msgBoxService.show('Is Andra in the Dungeon?', {
                icon: ADIcon.QUESTION,
                buttons: ADButtons.YesNo
            }).pipe(first()).subscribe(result => {
                if (result) {
                    mob.actions = 0;

                    msgBoxService.show('Is Any Hero in the LoS of Andra?', {
                        icon: ADIcon.QUESTION,
                        buttons: ADButtons.YesNo
                    }).pipe(first()).subscribe(result => {
                        if (result) {

                            mob.actionSubject.next(
                                `Andra attack the Hero with the lowest HP in LoS.<br>then Put Andra to out side of Dungeon.(Hero is not reachable but not dead)`
                            );
                        } else {
                            mob.actions = 0;
                            mob.actionSubject.next(
                                `Put Andra to out side of Dungeon.(Hero is not reachable but not dead)`
                            );
                        }
                    });
                } else {
                    let beenAttackHero = MD2Logic.getTargetHerosByFilter(heros, AttackTarget.LeastHp, true)[0];
                    mob.actionSubject.next(
                        `Place Andra in the same zone of ${MD2Logic.heroFullName(beenAttackHero)} and attack that Hero.`
                    );
                }
            });
        }

        this.mob.skills = [
            {
                description: `Deal ${damage} wound to another Hero with the lowest HP in LoS`,
                type: MobSkillType.Combat,
                skillRoll: 1
            } as MD2MobSkill];
        return this.mob;
    }
}
export class RMTheGhoulFactory extends CoreGameRMFactory {
    mobName: string = 'The Ghoul';
    generate(level: number): MobInfo {
        this.loadLevelInfo('The Ghoul', level);
        let health = 2;

        if (level < 3) {
            health = 5;
        } else if (level < 5) {
            health = 8;
        } else {
            health = 10;
        }

        this.mob.activateFunction = (mob, msgBoxService, heros) => {
            let actionResult = '';

            mob.actions = 0;
            msgBoxService.show('Is there any <b>Mob with minion</b> in The Ghoul zone?', {
                icon: ADIcon.QUESTION,
                buttons: ADButtons.YesNo
            }).pipe(first()).subscribe(result => {
                if (result) {
                    mob.unitRemainHp += health;
                    mob.actionSubject.next(
                        `Kill 1 minion in The Ghoul zone(player choose), The Ghoul heals ${health}.`
                    );
                } else {
                    mob.actionSubject.next(
                        `The Ghoul moves 3 Zones toward the closest Hero and attack him/her, if possible.`
                    );
                }
            });
        }

        this.mob.skills = [
            {
                description: `Move the closest <b>Mob with minion</b> 1 Zone toward The Ghoul.`,
                type: MobSkillType.Combat,
                skillRoll: 1
            } as MD2MobSkill];
        return this.mob;
    }
}
export class RMLyidanIncubusLordFactory extends CoreGameRMFactory {
    mobName: string = 'Lyidan, Incubus Lord';
    generate(level: number): MobInfo {
        this.loadLevelInfo('Lyidan, Incubus Lord', level);
        this.mob.activateFunction = (mob, msgBoxService, heros) => {
            let actionResult = '';

            mob.actions = 0;
            msgBoxService.show('Is Incubus Lord in a Light Zone?', {
                icon: ADIcon.QUESTION,
                buttons: ADButtons.YesNo
            }).pipe(first()).subscribe(result => {
                if (result) {
                    mob.unitRemainHp -= 3;
                    mob.actionSubject.next(
                        `The Incubus Lord got 3 Wounds, Move it to the closest Shadow Zone.`
                    );
                } else {
                    msgBoxService.show('Is there a Hero up to 3 Zones away(regardless of LoS) from The Incubus Lord?', {
                        icon: ADIcon.QUESTION,
                        buttons: ADButtons.YesNo
                    }).pipe(first()).subscribe(result => {
                        if (result) {
                            mob.actionSubject.next(
                                `Place The Incubus Lord in the zone of furthest Hero up to 3 Zones away.<br>` +
                                `Add 1 ${this.iconHtml(MD2Icon.Fire)} to that Hero and attack him/her.`
                            );
                        } else {
                            mob.actions = 2;
                            mob.actionSubject.next(
                                `The Incubus Lord 2 Actions`
                            );
                        }
                    });
                }
            });
        }

        this.mob.skills = [
            {
                description: `After combat, resolve all ${this.iconHtml(MD2Icon.Fire)} on the defending Hero(once per combat).`,
                type: MobSkillType.Attack,
                skillRoll: 1
            } as MD2MobSkill];
        return this.mob;
    }
}


export class RMBalrogFactory extends CoreGameRMFactory {
    mobName: string = 'Balrog';
    generate(level: number): MobInfo {
        this.loadLevelInfo('Balrog', level);
        this.mob.extraRule = `When Balrog is in the Dungeon, ${this.iconHtml(MD2Icon.Fire)} on Heros can't be removed, Heros still suffer its effects when activating.`
        this.mob.activateFunction = (mob, msgBoxService, heros) => {
            let actionResult = '';

            mob.actions = 0;
            let noFireHeros = heros.filter(h => h.fireToken == 0);
            if (noFireHeros.length == 0) {

                mob.actions = 3;
                mob.actionSubject.next(
                    `The Balrog gains 3 Actions`
                );

            } else {
                let fireTokens = Math.round(Math.random() * 2) + 1;
                mob.actionSubject.next(
                    `Balrog ,moves 2 Zones toward to ${MD2Logic.getTargetHerosHtml(noFireHeros)} and Each Hero in ${this.iconHtml(MD2Icon.Magic)} range takes ${fireTokens} ${this.iconHtml(MD2Icon.Fire)}`
                );
            }
        }

        this.mob.skills = [
            {
                description: `The Hero takes 1 ${this.iconHtml(MD2Icon.Fire)}`,
                type: MobSkillType.Combat,
                skillRoll: 1
            } as MD2MobSkill];
        return this.mob;
    }
}
export const CoreGameRMFactories = [
    new RMUndeadQueenFactory(),
    new RMAndraFactory(),
    new RMTheGhoulFactory(),
    new RMLyidanIncubusLordFactory(),
    new RMBalrogFactory()
];