import {
  world,
  Player,
  ItemStack,
  GameMode,
  Entity,
} from "@minecraft/server";
import { consumeDurability, getEquipmentItem, setEquipmentItem } from "lazuli-utils";

/**
 * Dispose the item when entity use it.
 * @param durability The durability to reduce.
 * @param item The item to be used.
 * @param entity The entity that used the item.
 * @param event
 */
function disposeItem(
  durability: number,
  item: ItemStack,
  entity: Entity,
  event?: (holder: Entity, item: ItemStack) => void
): void {
  const newItem = consumeDurability(item, durability, entity);
  setEquipmentItem(entity, newItem);
  if (!newItem && event) {
    event(entity, item);
  }
}


/**
 * Define a tool tag.
 * @category Need Registry
 */
export class WeaponTag {
  constructor(
    /**
     * The weapon tag.
     */
    public tag: string,
    /**
     * Additional options of the weapon.
     */
    public options?: WeaponOptions
  ) {
  }
  /**
   * Automatically consume durability for the tools.
   */
  listeningDurability() {
    world.afterEvents.playerBreakBlock.subscribe((event) => {
      const [PLAYER, ITEM] = [event.player, getEquipmentItem(event.player)];
      if (ITEM?.hasTag(this.tag)) {
        if (
          PLAYER.getGameMode() === GameMode.survival ||
          PLAYER.getGameMode() === GameMode.adventure
        ) {
          disposeItem(2, ITEM, PLAYER, this.options?.destroyedAfterEvents);
        }
      }
    });
    world.afterEvents.entityHitEntity.subscribe((event) => {
      const [ENTITY, ITEM] = [
        event.damagingEntity,
        getEquipmentItem(event.damagingEntity),
      ];
      if (ITEM?.hasTag(this.tag)) {
        if (ENTITY instanceof Player) {
          if (
            ENTITY.getGameMode() === GameMode.survival ||
            ENTITY.getGameMode() === GameMode.adventure
          ) {
            disposeItem(1, ITEM, ENTITY, this.options?.destroyedAfterEvents);
          }
        } else {
          disposeItem(1, ITEM, ENTITY, this.options?.destroyedAfterEvents);
        }
      }
    });
  }
}

/**
 * Define a tool.
 */
export class WeaponItem {
  constructor(
    /**
     * Item of the weapon.
     */
    public item: ItemStack,
    /**
     * Additional options of the weapon.
     */
    public options?: WeaponOptions
  ) {
  }
  /**
   * Automatically consume durability for the tools.
   */
  listeningDurability() {
    world.afterEvents.playerBreakBlock.subscribe((event) => {
      const [PLAYER, ITEM] = [event.player, getEquipmentItem(event.player)];
      if (ITEM?.typeId === this.item.typeId) {
        if (
          PLAYER.getGameMode() === GameMode.survival ||
          PLAYER.getGameMode() === GameMode.adventure
        ) {
          disposeItem(2, ITEM, PLAYER, this.options?.destroyedAfterEvents);
        }
      }
    });
    world.afterEvents.entityHitEntity.subscribe((event) => {
      const [ENTITY, ITEM] = [
        event.damagingEntity,
        getEquipmentItem(event.damagingEntity),
      ];
      if (ITEM?.typeId === this.item.typeId) {
        if (ENTITY instanceof Player) {
          if (
            ENTITY.getGameMode() === GameMode.survival ||
            ENTITY.getGameMode() === GameMode.adventure
          ) {
            disposeItem(1, ITEM, ENTITY, this.options?.destroyedAfterEvents);
          }
        } else {
          disposeItem(1, ITEM, ENTITY, this.options?.destroyedAfterEvents);
        }
      }
    });
  }
}

/**
 * Type of the weapon.
 */
export enum WeaponType {
  /**
   * Define the weapon is a sword.
   */
  sword,
  /**
   * Define a custom sword.
   */
  custom,
}

export interface WeaponOptions {
  /**
   * Type of the tool.
   */
  type?: WeaponType;
  /**
   * Trigger events when the tool has been destroyed.
   */
  destroyedAfterEvents?: (holder: Entity,item: ItemStack) => void;
}
