import { Component } from '@angular/core';
import { DataService } from 'src/services/data/data.service';
import { ModalService } from 'src/services/modal/modal.service';
import { SpellslotsModalComponent } from './spellslots-modal/spellslots-modal.component';

@Component({
  selector: 'spellslots-table',
  templateUrl: './spellslots.component.html',
  styleUrls: ['./spellslots.component.scss'],
})
export class SpellslotsComponent {
  public spellslots: any[] = [];
  public showSpellslots: boolean = false;
  public kiPoints: any;
  public spellcastingAttribute: string = '';
  public proficiencyBonus: number = 2;
  public attributeValue: number = 0;
  public isMonk: boolean = true;

  public spellAttackModifier: number = 0;
  public spellSaveDC: number = 0;

  public slotNumber: number = 1;

  public constructor(
    public dataAccessor: DataService,
    public modalAccessor: ModalService,
  ) {
    this.isMonk = this.dataAccessor.characterData.class === 'Monk';
  }

  public ngOnInit(): void {
    const spells = this.dataAccessor.spellslots;
    const kiPoints = this.dataAccessor.kiPoints;
    this.spellslots = spells.spellslots;
    this.showSpellslots = spells.showSpellslots;
    this.spellcastingAttribute = spells.spellcastingAttribute;
    this.kiPoints = kiPoints;
    this.subscribeToProficiency();
    this.subscribeToAttribute();
  }

  public ngAfterViewInit(): void {
    setTimeout(() => {
      this.spellslots.forEach((_, levelIndex) => {
        this.correctSpellslotsView(levelIndex);
      });
      this.correctKiPointsView();
    }, 10);
  }

  // FUNCTIONS

  public openModal(): void {
    this.modalAccessor.openModal(SpellslotsModalComponent, {
      kiPoints: JSON.parse(JSON.stringify(this.kiPoints)),
      spellslots: JSON.parse(JSON.stringify(this.spellslots)),
      showSpellslots: this.showSpellslots,
      isMonk: this.isMonk,
    });
    const resultSubscription = this.modalAccessor.result$.subscribe(
      (result) => {
        if (result.state === 'update') {
          this.updateSlotsAndPoints(result.data);
        }
        resultSubscription.unsubscribe();
      },
    );
  }

  private calculateModifiers(): void {
    const spellcastingAttribute = this.spellcastingAttribute;

    if (spellcastingAttribute !== undefined) {
      const modifier = Math.floor((this.attributeValue - 10) / 2);
      this.spellAttackModifier = modifier + this.proficiencyBonus;
      this.spellSaveDC = 8 + modifier + this.proficiencyBonus;
    }
  }

  private subscribeToAttribute(): void {
    if (
      this.spellcastingAttribute !== undefined &&
      this.spellcastingAttribute !== null
    ) {
      const command =
        'this.dataAccessor.' +
        this.spellcastingAttribute.toLowerCase() +
        '$.subscribe((attribute) => {this.attributeValue = attribute.value; this.calculateModifiers();});';
      eval(command);
    }
  }

  private subscribeToProficiency(): void {
    this.dataAccessor.proficiency$.subscribe((value) => {
      this.proficiencyBonus = value;
      this.calculateModifiers();
    });
  }

  // ki points

  public handleUsedKiPoints(pointIndex: number, eventTarget: any): void {
    if (eventTarget.checked) {
      this.kiPoints.usedPoints++;
      if (pointIndex + 1 !== this.kiPoints.usedPoints) {
        this.correctKiPointsView();
      }
    } else {
      this.kiPoints.usedPoints--;
      if (pointIndex !== this.kiPoints.usedPoints) {
        this.correctKiPointsView();
      }
    }
    this.updateKiPointsDatabase();
  }

  private correctKiPointsView(): void {
    const totalKiPoints = this.kiPoints.totalPoints;
    const usedKiPoints = this.kiPoints.usedPoints;
    for (let kiIndex = 0; kiIndex < usedKiPoints; kiIndex++) {
      setTimeout(() => {
        (
          document.getElementById('checkbox' + kiIndex) as HTMLInputElement
        ).checked = true;
      });
    }
    for (let kiIndex = usedKiPoints; kiIndex < totalKiPoints; kiIndex++) {
      setTimeout(() => {
        (
          document.getElementById('checkbox' + kiIndex) as HTMLInputElement
        ).checked = false;
      });
    }
  }

  // spellslots

  public handleUsedSlots(
    levelIndex: number,
    slotIndex: number,
    eventTarget: any,
  ) {
    // if now checked, it means the slot was just used.
    if (eventTarget.checked) {
      this.spellslots[levelIndex].usedSlots++;
      if (slotIndex + 1 !== this.spellslots[levelIndex].usedSlots) {
        this.correctSpellslotsView(levelIndex);
      }
    } else {
      this.spellslots[levelIndex].usedSlots--;
      if (slotIndex !== this.spellslots[levelIndex].usedSlots) {
        this.correctSpellslotsView(levelIndex);
      }
    }
    this.updateSpellslotDatabase();
  }

  public correctSpellslotsView(levelIndex: number): void {
    const totalSlots = this.spellslots[levelIndex].totalSlots;
    const usedSlots = this.spellslots[levelIndex].usedSlots;
    for (let slotIndex = 0; slotIndex < usedSlots; slotIndex++) {
      setTimeout(() => {
        (
          document.getElementById(
            'checkbox' + levelIndex + '-' + slotIndex,
          ) as HTMLInputElement
        ).checked = true;
      });
    }
    for (let slotIndex = usedSlots; slotIndex < totalSlots; slotIndex++) {
      setTimeout(() => {
        (
          document.getElementById(
            'checkbox' + levelIndex + '-' + slotIndex,
          ) as HTMLInputElement
        ).checked = false;
      });
    }
  }

  // general

  public getArray(length: number): any[] {
    return Array.from({ length: length });
  }

  public isNotEmptyObject(obj: object): boolean {
    return Object.keys(obj).length !== 0;
  }

  public updateSpellslotDatabase(): void {
    this.dataAccessor.spellslots = {
      spellslots: this.spellslots,
      showSpellslots: this.showSpellslots,
      spellcastingAttribute: this.spellcastingAttribute,
    };
  }

  public updateKiPointsDatabase(): void {
    this.dataAccessor.kiPoints = this.kiPoints;
  }

  public updateSlotsAndPoints(data: any): void {
    this.spellslots = data.spellslots.spellslots;
    this.showSpellslots = data.spellslots.showSpellslots;
    this.kiPoints = data.kiPoints;

    setTimeout(() => {
      this.spellslots.forEach((_, levelIndex) => {
        this.correctSpellslotsView(levelIndex);
      });
      this.correctKiPointsView();
    }, 200);

    this.updateSpellslotDatabase();
    this.updateKiPointsDatabase();
  }
}
