import * as mc from "@minecraft/server";
import { SafetyCheckedPlayer, getAllPlayersSafe } from "./entity";
import { clamp } from "./math";
import { mcerror } from "./log";
import { GlobalNamespace } from "./namespace";
import { waitForEvent, waitForLoopEvent } from "./events";
/**
 * @remarks Modifies the durability of an item in a given entity's specified equipment slot.
 * @param entity The safety checked entity who's equipment to modify.
 * @param equipmentSlot The equipment slot to modify the equipment in.
 * @param durabilityChangeAmount The amount by which to change the durability, use negative values to decrease the durability.
 * @example
 * ```typescript
 * modifyEquipmentDurability(new SafetyCheckedEntity(player), mc.EquipmentSlot.Mainhand, -1); // Decreases durability of held item by 1
 * ```
 */
export function modifyEquipmentDurability(entity, equipmentSlot, durabilityChangeAmount) {
    if (entity.matches({ gameMode: mc.GameMode.creative }))
        return;
    const equipment = entity.getComponent(mc.EntityEquippableComponent.componentId);
    if (!equipment)
        return;
    const item = equipment.getEquipment(equipmentSlot);
    if (!item)
        return;
    const durability = item.getComponent(mc.ItemDurabilityComponent.componentId);
    if (!durability) {
        mcerror(`${item.typeId} Has No Durability Component`);
        return;
    }
    ;
    durability.damage = clamp(durability.damage + (durabilityChangeAmount * -1), 0, durability.maxDurability);
    if (durability.damage === durability.maxDurability) {
        mc.world.playSound('random.break', entity.location);
        equipment.setEquipment(equipmentSlot);
    }
    else {
        equipment.setEquipment(equipmentSlot, item);
    }
}
const CUSTOM_ITEM_RECORD = {};
/**
 * @remarks How should this custom item handle a melee animation?
 */
export var CustomItemMeleeType;
(function (CustomItemMeleeType) {
    /**
     * @remarks Performs a vanilla melee attack. Expects the third person idle to have `override_previous_animation` true.
     */
    CustomItemMeleeType[CustomItemMeleeType["vanilla"] = 0] = "vanilla";
    /**
     * @remarks Performs the custom attack animation **instead** of the vanilla melee. Requires the first and third person animations to have `override_previous_animation` true and the attachable's transition from idle to be `"attack": "query.is_using_item || query.is_name_any('<namespace>:attack')"`.
     */
    CustomItemMeleeType[CustomItemMeleeType["meleeOverride"] = 1] = "meleeOverride";
    /**
     * @remarks Performs the custom attack animation **instead** of the vanilla melee and does **not** perform the attack on interact. Requires the first and third person animations to have `override_previous_animation` true and the attachable's transition from idle to be `"attack": "query.is_using_item || query.is_name_any('<namespace>:attack')"`.
     */
    CustomItemMeleeType[CustomItemMeleeType["meleeOnly"] = 2] = "meleeOnly";
})(CustomItemMeleeType || (CustomItemMeleeType = {}));
/**
 * @remarks Initialized an array of {@link ICustomItem}s to play animations and perform effects.
 * @param items An array of {@link ICustomItem}s.
 */
export function initializeCustomItem(items) {
    items.forEach(item => {
        var _a, _b;
        let effectsCallback = (player) => {
            var _a, _b;
            if ((_a = item.options) === null || _a === void 0 ? void 0 : _a.itemCallback) {
                item.options.itemCallback(player);
            }
            if ((_b = item.options) === null || _b === void 0 ? void 0 : _b.meleeAttack) {
                item.options.meleeAttack.attack(player);
            }
        };
        if (((_a = item.options) === null || _a === void 0 ? void 0 : _a.itemCallback) && item.options.meleeAttack) {
            item.options.meleeAttack.addSwingCallback(item.options.itemCallback);
            effectsCallback = (player) => {
                item.options.meleeAttack.attack(player);
            };
        }
        //#region CUSTOM ITEM ACS
        switch ((_b = item.options) === null || _b === void 0 ? void 0 : _b.meleeAnimation) {
            case CustomItemMeleeType.meleeOverride:
                CUSTOM_ITEM_RECORD[item.typeId] = (player, attacking) => {
                    const itemShortName = item.typeId.split(':').pop();
                    // Custom Attacks Melee Transition
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.first_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.third_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    // Custom Idles
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`, {
                        stopExpression: `query.is_name_any('${GlobalNamespace.Namespace}attack') || v.attack_time`,
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.first_person`,
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`, {
                        stopExpression: `query.is_name_any('${GlobalNamespace.Namespace}attack') || v.attack_time`,
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.third_person`,
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    if (!attacking)
                        return;
                    // Custom Attacks Interact
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.first_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.third_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    effectsCallback(player);
                };
                break;
            case CustomItemMeleeType.meleeOnly:
                CUSTOM_ITEM_RECORD[item.typeId] = (player, attacking) => {
                    const itemShortName = item.typeId.split(':').pop();
                    // Custom Attacks Melee Transition
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.first_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.third_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    // Custom Idles
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`, {
                        stopExpression: "v.attack_time > 0",
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.first_person`,
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`, {
                        stopExpression: `v.attack_time > 0`,
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.third_person`,
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                };
                break;
            default:
                CUSTOM_ITEM_RECORD[item.typeId] = (player, attacking) => {
                    const itemShortName = item.typeId.split(':').pop();
                    // Vanilla Punch
                    player.playAnimation(`empty`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`,
                        stopExpression: "v.attack_time <= 0",
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    // Custom Idles
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`, {
                        stopExpression: "false",
                        nextState: "default",
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`, {
                        stopExpression: `v.attack_time > 0 && !v.is_first_person && q.is_item_name_any('slot.weapon.mainhand', 0, '${item.typeId}')`,
                        nextState: `empty`,
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    if (!attacking)
                        return;
                    // Custom Attacks
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.first_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.first_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.first_person`,
                    });
                    player.playAnimation(`animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.attack.third_person`, {
                        nextState: `animation.${GlobalNamespace.NamespaceUnformatted}.player.${itemShortName}.idle.third_person`,
                        stopExpression: "query.any_animation_finished || (!v.playing_custom_attack)",
                        blendOutTime: 0,
                        controller: `${itemShortName}.third_person`,
                    });
                    effectsCallback(player);
                };
                break;
        }
        //#endregion
        waitForEvent(100, () => getAllPlayersSafe().forEach(player => CUSTOM_ITEM_RECORD[item.typeId](player, false)));
    });
    mc.world.afterEvents.itemStartUse.subscribe(event => {
        if (CUSTOM_ITEM_RECORD[event.itemStack.typeId]) {
            CUSTOM_ITEM_RECORD[event.itemStack.typeId](new SafetyCheckedPlayer(event.source), true);
        }
    });
    mc.world.afterEvents.playerSpawn.subscribe(event => {
        waitForEvent(100, () => items.forEach(item => CUSTOM_ITEM_RECORD[item.typeId](new SafetyCheckedPlayer(event.player), false)));
    });
    // Handles Weakness For Melee Weapons
    const meleeItems = items.filter(item => { var _a; return (_a = item.options) === null || _a === void 0 ? void 0 : _a.meleeAnimation; }).map(item => item.typeId);
    const meleePlayers = {};
    if (meleeItems.length) {
        waitForLoopEvent(10, () => {
            getAllPlayersSafe().forEach(player => {
                var _a, _b;
                if (meleeItems.includes(String((_b = (_a = player.Equipment) === null || _a === void 0 ? void 0 : _a.getEquipment(mc.EquipmentSlot.Mainhand)) === null || _b === void 0 ? void 0 : _b.typeId))) {
                    player.addEffect("weakness", 15, { amplifier: 255, showParticles: false });
                    player.runCommand("hud @s hide status_effects");
                    meleePlayers[player.id] = true;
                }
                else if (meleePlayers[player.id]) {
                    player.removeEffect("weakness");
                    player.runCommand("hud @s reset status_effects");
                    meleePlayers[player.id] = false;
                }
            });
            return false;
        });
    }
}
