import { ChangeDetectorRef, Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { NbDialogRef } from '@nebular/theme';
import { concatMap, find, defaultIfEmpty, first, map, switchMap } from 'rxjs/operators';
import { FileService } from '../../../../services/file.service';
import { MD2Service } from '../../../../services/MD2/md2.service';
import { MsgBoxService } from '../../../../services/msg-box.service';
import { StateService } from '../../../../services/state.service';
import { StringUtils } from '../../../../utilities/string-utils';
import { AttackInfo, AttackTarget, AttackType, MD2HeroInfo, MD2Icon, MobDlgType, MobInfo, MobType } from '../../massive-darkness2.model';
import { MD2ComponentBase } from '../../MD2Base';
import { ADButtons, ADIcon } from '../../../../ui/alert-dlg/alert-dlg.model';
import { MobSkillType } from '../../massive-darkness2.model.boss';
import { Observable, from, of } from 'rxjs';
import { MD2MobSkill } from '../../massive-darkness2.db.model';

type SkillResolutionResult = { result: boolean; skill: MD2MobSkill | null };

@Component({
  selector: 'ngx-spawn-mob-dlg',
  templateUrl: './spawn-mob-dlg.component.html',
  styleUrls: ['./spawn-mob-dlg.component.scss']
})
export class SpawnMobDlgComponent extends MD2ComponentBase implements OnInit {
  MobDlgType = MobDlgType;
  MobType = MobType;
  mode: MobDlgType;
  cardTitle: string;
  title: string;
  titleHtml: string;
  MD2Icon = MD2Icon;
  mob: MobInfo;
  actionInfoHtml: string;
  beenAttackedHero = [] as MD2HeroInfo[];
  attackTarget: string;
  otherAttackTarget: string;
  constructor(
    private dlgRef: NbDialogRef<SpawnMobDlgComponent>,
    private msgBoxService: MsgBoxService,
    public md2Service: MD2Service,
    protected stateService: StateService,
    protected route: ActivatedRoute,
    protected cdRef: ChangeDetectorRef,
  ) {
    super(md2Service, stateService, route, cdRef);
  }
  activeSkill: MD2MobSkill = null;;
  ngOnInit(): void {
    //this.mob = new MobInfo(this.mob);
    if (this.mode == MobDlgType.Spawn && this.mob.type == MobType.Mob) {
      this.mob.attackInfos = [new AttackInfo(MD2Icon.Melee), new AttackInfo(MD2Icon.Range), new AttackInfo(MD2Icon.Magic)];
    } else if (this.mode == MobDlgType.Activating) {
      if (this.mob.skills) {

        //this.mobActivate(this.mob, this.md2Service.info.heros);
        //this.mob.activateFunction(this.mob, this.md2Service.msgBoxService, this.md2Service.info.heros);
        this.mobActivate(this.mob, this.md2Service.info.heros).pipe(first()).subscribe(result => {
          if (result && result.skill) {
            this.activeSkill = result.skill;
            //this.actionInfoHtml = `<h4>${result.skill.name}</h4><div>${result.skill.description}</div>`;
          }
          if (this.mob.type == MobType.Mob) {
            this.mob.actions = 2;
          } else {
            if (result && result.skill) {
              this.mob.actions = 1;
            } else {
              this.mob.actions = 2;
              this.activeSkill = { name: 'Normal Action', description: `${this.mob.name} Gains 2 Actions.` } as MD2MobSkill;
              //this.actionInfoHtml = `${this.mob.name} Gains 2 Actions.`;
            }
          }

        });
      }
    }
    this.mob.uiWounds = 0;
    this.mob.uiFrozenTokens = 0;
    this.mob.uiFrozenTokens = 0;
    this.initTitleHtml();
  }

  mobActivate(mob: MobInfo, heros: MD2HeroInfo[]): Observable<SkillResolutionResult> {
    switch (mob.type) {
      case MobType.Mob:
        return of({ result: false, skill: null } as SkillResolutionResult);
      case MobType.RoamingMonster:
        if (!mob.skills || mob.skills.length === 0) {
          return of({ result: false, skill: null } as SkillResolutionResult);
        }

        const orderedSkills = mob.skills
          .filter(s => [MobSkillType.ConditionalSkill, MobSkillType.OtherWiseSkill].includes(s.type))
          .sort((a, b) => (a.seq ?? Number.MAX_SAFE_INTEGER) - (b.seq ?? Number.MAX_SAFE_INTEGER));

        if (orderedSkills.length === 0) {
          return of({ result: false, skill: null } as SkillResolutionResult);
        }

        return from(orderedSkills).pipe(
          concatMap(skill => this.resolveSkillPrompt(skill)),
          find(resolution => resolution.result === true),
          defaultIfEmpty({ result: false, skill: null } as SkillResolutionResult)
        );
      case MobType.Boss:
      default:
        return of({ result: false, skill: null } as SkillResolutionResult);
    }
  }

  private resolveSkillPrompt(skill: MD2MobSkill): Observable<SkillResolutionResult> {
    if (skill.type === MobSkillType.OtherWiseSkill) {
      return of({ result: true, skill } as SkillResolutionResult);
    }

    const title = 'Resolve Skill?';
    const prompt = skill.skillCondition;

    return this.msgBoxService.show(title, {
      text: prompt,
      icon: ADIcon.QUESTION,
      buttons: ADButtons.YesNo
    }).pipe(
      map(answer => ({ result: !!answer, skill } as SkillResolutionResult))
    );
  }

  submit() {
    if (this.mode == MobDlgType.Spawn) {

      this.mob.attackInfos = this.mob.attackInfos.filter(a => a.yellow > 0 || a.orange > 0 || a.red > 0);
    }
    switch (this.mode) {
      case MobDlgType.Spawn:
        this.mob.attackInfos = this.mob.attackInfos.filter(a => a.yellow > 0 || a.orange > 0 || a.red > 0);
        break;
      case MobDlgType.Activating:
        break;
      case MobDlgType.BeenAttacked:
        break;
      case MobDlgType.PreView:
      default:
        break;
    }
    this.md2Service.info.showAttackBtn = false;
    this.md2Service.refreshUI$.next();
    this.dlgRef.close(this.mob);
  }
  cancel() {
    this.dlgRef.close();
  }
  initTitleHtml() {

    this.cardTitle = MobType[this.mob.type];

    let htmlText = '';
    if (this.mode == MobDlgType.Spawn) {
      htmlText = `${this.mob.description} Shows Up`;
    } else if (this.mode == MobDlgType.Activating) {
      let targetType = null as AttackTarget;
      let randomAttack = Math.random() * AttackTarget.LowestLevel;
      const values = Object.values(AttackTarget);

      const stringKeys = Object
        .keys(AttackTarget)
        .filter((v) => isNaN(Number(v)))
      for (let i = 0; i < stringKeys.length; i++) {
        const element = AttackTarget[stringKeys[i]];

        if (element >= randomAttack) {
          targetType = element;
          break;
        }
      }
      switch (targetType) {
        case AttackTarget.LeastHp:
          let lowestHp = Math.min(...this.md2Service.heros.map(h => h.hp));
          this.beenAttackedHero = this.md2Service.heros.filter(h => h.hp == lowestHp);
          //this.otherAttackTarget = 'attacking the other <b>Lowest HP</b> hero.';
          break;
        case AttackTarget.HighestHp:
          let highestHp = Math.max(...this.md2Service.heros.map(h => h.hp));
          this.beenAttackedHero = this.md2Service.heros.filter(h => h.hp == highestHp);
          //this.otherAttackTarget = 'attacking the other <b>Highest HP</b> hero.';
          break;
        case AttackTarget.HighestMp:
          let highestMp = Math.max(...this.md2Service.heros.map(h => h.mp));
          this.beenAttackedHero = this.md2Service.heros.filter(h => h.mp == highestMp);
          //this.otherAttackTarget = 'attacking the other <b>Highest Mp</b> hero.';
          break;
        case AttackTarget.LowestLevel:
          let lowestLevel = Math.max(...this.md2Service.heros.map(h => h.level));
          this.beenAttackedHero = this.md2Service.heros.filter(h => h.level == lowestLevel);
          //this.otherAttackTarget = 'attacking the other <b>Lowest Level</b> hero.';
          break;
        case AttackTarget.Random:
        default:
          this.beenAttackedHero = [this.md2Service.heros[Math.round(Math.random() * (this.md2Service.heros.length - 1))]];
          //this.otherAttackTarget = 'Just act like normal.';
          break;
      }
      let attackedHeros = StringUtils.makeCommaSeparatedString(this.beenAttackedHero.map(h => this.md2Service.heroFullName(h)), true, true);
      this.attackTarget = `Attacking <b>${attackedHeros}</b> first if possible.`;
      htmlText = `${this.title}`;
    } else {
      htmlText = `${this.mob.description}`;
    }
    this.titleHtml = htmlText;
  }


  public get headerStatus(): string {
    switch (this.mode) {
      case MobDlgType.Spawn:
        return 'warning';
        break;
      case MobDlgType.Activating:
        return 'danger';
        break;
      case MobDlgType.BeenAttacked:
        return 'info';
        break;
      case MobDlgType.PreView:
      default:
        return '';
        break;
    }
  }

  public get submitBtnText(): string {
    switch (this.mode) {
      case MobDlgType.Activating:
        return 'Next';
        break;
      case MobDlgType.BeenAttacked:
        return 'Attack!!';
        break;
      case MobDlgType.PreView:
      case MobDlgType.Spawn:
      default:
        return 'Close';
    }
  }
}
