import { Component, EventEmitter, Output } from '@angular/core';
import { DataService } from 'src/services/data/data.service';
import { Attribute, Weapon } from 'src/interfaces/interfaces';
import { CdkDragDrop, moveItemInArray } from '@angular/cdk/drag-drop';
import { DetailsService } from 'src/services/details/details.service';
import { WeaponDetailsComponent } from './weapon-details/weapon-details.component';
import { ModalService } from 'src/services/modal/modal.service';
import { WeaponModalComponent } from './weapon-modal/weapon-modal.component';

@Component({
  selector: 'weapon-table',
  templateUrl: './weapon-table.component.html',
  styleUrls: ['./weapon-table.component.scss'],
})
export class WeaponTableComponent {
  @Output() public createNewWeapon: EventEmitter<void> =
    new EventEmitter<void>();

  @Output() public updateWeaponEvent: EventEmitter<any> =
    new EventEmitter<any>();

  public weapons!: Weapon[];
  public damageModifiers: string[] = [
    '0',
    '0',
    '0',
    '0',
    '0',
    '0',
    '0',
    '0',
    '0',
    '0',
  ];
  public isMonk: boolean = false;
  public strengthValue: number = 0;
  public dexterityValue: number = 0;

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

  public ngOnInit(): void {
    this.dataAccessor.strength$.subscribe((newValue: Attribute) => {
      this.strengthValue = newValue.value;
      if (this.weapons) {
        this.calculateDamageModifierArray();
      }
    });
    this.dataAccessor.dexterity$.subscribe((newValue: Attribute) => {
      this.dexterityValue = newValue.value;
      if (this.weapons) {
        this.calculateDamageModifierArray();
      }
    });
    this.weapons = this.dataAccessor.favoriteWeapons;
    this.calculateDamageModifierArray();
  }

  /**
   * Calculates the whole damage modifier array.
   * Calls the single damage modifier calculation for each weapon.
   */
  private calculateDamageModifierArray(): void {
    this.weapons.forEach((_, index) => {
      this.calculateSingleDamageModifier(index);
    });
  }

  private calculateSingleDamageModifier(index: number): void {
    let value: number = 0;
    let bonus: number = 0;
    const weapon: Weapon = this.weapons[index];
    if (weapon.useAttributeModifier) {
      if (this.isMonk || weapon.isFinesse) {
        value = Math.max(this.strengthValue, this.dexterityValue);
      } else if (weapon.isRanged) {
        value = this.dexterityValue;
      } else {
        value = this.strengthValue;
      }
    } else {
      value = 10;
    }
    if (weapon.isMagical) {
      bonus = weapon.magicBonus!;
    }
    if (weapon.hasAdditionalDamage) {
      bonus += weapon.additionalDamage!;
    }
    this.damageModifiers[index] = this.calculateModifier(value, bonus);
  }

  public dropWeapons(event: CdkDragDrop<string[]>): void {
    moveItemInArray(this.weapons, event.previousIndex, event.currentIndex);
    moveItemInArray(
      this.damageModifiers,
      event.previousIndex,
      event.currentIndex,
    );
    this.updateWeaponInDatabase();
  }

  public updateWeaponInDatabase(): void {
    this.dataAccessor.favoriteWeapons = this.weapons;
  }

  public addWeapon(weapon: Weapon) {
    this.weapons.push(weapon);
    this.calculateDamageModifierArray();
    this.updateWeaponInDatabase();
  }

  public openDetailsPanel(index: number): void {
    this.detailsAccessor.openPanel(WeaponDetailsComponent, {
      weapon: this.weapons[index],
      damageModifier: this.damageModifiers[index],
    });
    const resultSubscription = this.detailsAccessor.result$.subscribe(
      (result) => {
        if (result.state === 'delete') {
          this.deleteWeapon(index);
        } else if (result.state === 'update') {
          this.openModal(true, index);
        }
        resultSubscription.unsubscribe();
      },
    );
  }

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

  public updateWeapon(weapon: Weapon, index: number): void {
    this.weapons[index] = weapon;
    this.calculateSingleDamageModifier(index);
    this.updateWeaponInDatabase();
  }

  public deleteWeapon(index: number): void {
    this.weapons.splice(index, 1);
    this.calculateDamageModifierArray();
    this.updateWeaponInDatabase();
  }

  ////// Calculation Helpers

  private calculateModifier(attributeValue: number, bonus: number): string {
    let mod: number = Math.floor((attributeValue - 10) / 2) + bonus;
    if (mod > 0) {
      return '+' + mod;
    } else {
      return mod.toString();
    }
  }
}
