import { Component } from '@angular/core';
import {
  CdkDragDrop,
  CdkDropList,
  CdkDrag,
  moveItemInArray,
} from '@angular/cdk/drag-drop';
import { DataService } from 'src/services/data/data.service';
import { Ability } from 'src/interfaces/interfaces';
import { AbilityDetailsComponent } from './ability-details/ability-details.component';
import { DetailsService } from 'src/services/details/details.service';
import { ModalService } from 'src/services/modal/modal.service';
import { AbilityModalComponent } from './ability-modal/ability-modal.component';

@Component({
  selector: 'ability-table',
  templateUrl: './ability-table.component.html',
  styleUrls: ['./ability-table.component.scss'],
})
export class AbilityTableComponent {
  public abilities!: Ability[];

  public isToUpdate: boolean = false;
  public abilityToUpdate: Ability | undefined;
  public updateAbilityIndex: number | undefined;

  // LIFECYCLE

  public constructor(
    public dataAccessor: DataService,
    private detailsAccessor: DetailsService,
    private modalAccessor: ModalService,
  ) {}

  public ngOnInit(): void {
    this.abilities = this.dataAccessor.abilities;
  }

  public ngAfterViewInit(): void {
    this.abilities.forEach((ability, abilityIndex) => {
      this.correctChargesView(abilityIndex);
    });
  }

  // FUNCTIONS

  public openModal(isUpdate: boolean, index?: number): void {
    this.modalAccessor.openModal(AbilityModalComponent, {
      ability:
        index !== undefined
          ? JSON.parse(JSON.stringify(this.abilities[index]))
          : undefined,
      isUpdate: isUpdate,
    });
    const resultSubscription = this.modalAccessor.result$.subscribe(
      (result) => {
        if (result.state === 'update') {
          this.updateAbility(result.data, index!);
        } else if (result.state === 'add') {
          this.addAbility(result.data);
        }
        resultSubscription.unsubscribe();
      },
    );
  }

  public handleChangedCharges(abilityindex: number, CheckBoxRef: any): void {
    const newValue = CheckBoxRef.checked;
    // checked now, so a charge was used -> decrease
    if (newValue) {
      this.abilities[abilityindex].currentlyUsedCharges++;
      // else increase
    } else {
      this.abilities[abilityindex].currentlyUsedCharges--;
    }
    this.correctChargesView(abilityindex);
    this.updateDatabase();
  }

  /**
   * Ticks the first x checkboxes of an ability, where x is the amount of currently used charges.
   * @param abilityIndex The Index of the ability to correct the charges view for
   * @returns void
   */
  public correctChargesView(abilityIndex: number): void {
    // if there are more than 9 charges, the charges are not handled by checkboxes.
    if (this.abilities[abilityIndex].charges > 9) return;
    const charges = this.abilities[abilityIndex].charges;
    const currentlyUsedCharges =
      this.abilities[abilityIndex].currentlyUsedCharges;
    for (
      let chargeIndex = 0;
      chargeIndex < currentlyUsedCharges;
      chargeIndex++
    ) {
      setTimeout(() => {
        (
          document.getElementById(
            'checkbox' + abilityIndex + '-' + chargeIndex,
          ) as HTMLInputElement
        ).checked = true;
      });
    }
    for (
      let chargeIndex = currentlyUsedCharges;
      chargeIndex < charges;
      chargeIndex++
    ) {
      setTimeout(() => {
        (
          document.getElementById(
            'checkbox' + abilityIndex + '-' + chargeIndex,
          ) as HTMLInputElement
        ).checked = false;
      });
    }
  }

  public updateDatabase(): void {
    this.dataAccessor.abilities = this.abilities;
  }

  // add
  public addAbility(ability: Ability): void {
    this.abilities.push(ability);
    this.updateDatabase();
  }

  //  update
  public updateAbility(ability: Ability, index: number): void {
    this.abilities[index] = ability;
    this.updateDatabase();
    this.correctChargesView(index);
  }

  // delete
  private deleteAbility(index: number): void {
    this.abilities.splice(index, 1);
    this.updateDatabase();
  }
  // DETAILS

  public openDetailsPanel(index: number): void {
    this.detailsAccessor.openPanel(AbilityDetailsComponent, {
      ability: this.abilities[index],
    });
    const resultSubscription = this.detailsAccessor.result$.subscribe(
      (result) => {
        if (result.state === 'delete') {
          this.deleteAbility(index);
        } else if (result.state === 'update') {
          this.openModal(true, index);
        }
        resultSubscription.unsubscribe();
      },
    );
  }

  // UTILITY

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

  public drop(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this.abilities, event.previousIndex, event.currentIndex);
    this.updateDatabase();
  }

  public removeUsage(abilityIndex: number): void {
    if (this.abilities[abilityIndex].currentlyUsedCharges > 0) {
      this.abilities[abilityIndex].currentlyUsedCharges--;
      this.updateDatabase();
    }
  }

  public addUsage(abilityIndex: number): void {
    if (
      this.abilities[abilityIndex].currentlyUsedCharges <
      this.abilities[abilityIndex].charges
    ) {
      this.abilities[abilityIndex].currentlyUsedCharges++;
      this.updateDatabase();
    }
  }
}
