import { EquipmentSlot, ItemStack, GameMode, world, } from "@minecraft/server";
/**
 * Checks if a player is in a specific game mode.
 * @param player - The player to check.
 * @param mode - The game mode to check against.
 * @returns A boolean indicating whether the player is in the specified game mode.
 */
export function isGameMode(player, mode) {
    return (player.dimension
        .getPlayers({ location: player.location, maxDistance: 1, gameMode: mode })
        .filter((p) => p.id === player.id).length > 0);
}
/**
 * Retrieves the game mode of a player.
 *
 * @param player - The player for which to retrieve the game mode.
 * @param orElse - The default game mode to return if the player's game mode is not found.
 * @returns The game mode of the player, or the default game mode if not found.
 */
export function getGameMode(player, orElse = GameMode.survival) {
    for (const mode of Object.values(GameMode)) {
        if (isGameMode(player, mode))
            return mode;
    }
    return orElse;
}
/**
 * Retrieves the item in the specified equipment slot for a player.
 * @param player - The player entity.
 * @param slot - The equipment slot to retrieve the item from.
 * @returns The item in the specified equipment slot, or undefined if no item is found.
 */
export function getItemInSlot(player, slot) {
    const equippableComponent = player.getComponent("minecraft:equippable");
    if (!equippableComponent)
        return undefined;
    return equippableComponent.getEquipment(slot);
}
/**
 * Sets an item in the specified equipment slot for a player.
 *
 * @param player - The player entity.
 * @param slot - The equipment slot to set the item in.
 * @param itemStack - The item stack to set in the slot. If not provided, the slot will be cleared.
 */
export function setItemInSlot(player, slot, itemStack) {
    const equippableComponent = player.getComponent("minecraft:equippable");
    equippableComponent.setEquipment(slot, itemStack);
}
/**
 * Adds an item to the inventory of an entity.
 * If the entity's inventory is full, it will drop the excess items on the ground.
 * @param entity - The entity to add the item to.
 * @param itemStack - The item stack to add to the inventory.
 * @param options - Additional options for adding the item to the inventory.
 */
export function addItemToInventory(entity, itemStack, options) {
    const inventory = entity.getComponent("inventory");
    const container = inventory?.container;
    if (!container) {
        entity.dimension.spawnItem(itemStack, entity.location);
        return;
    }
    if (inventory.container.emptySlotsCount === 0) {
        let spaceRemaining = 0;
        for (let slotId = 0; slotId < container.size; slotId++) {
            const slot = container.getSlot(slotId);
            if (slot.getItem()?.typeId === itemStack.typeId) {
                spaceRemaining += Math.max(slot.maxAmount - slot.amount, 0);
                if (spaceRemaining >= itemStack.amount)
                    break;
            }
        }
        const overflowAmount = itemStack.amount - spaceRemaining;
        if (overflowAmount > 0) {
            const droppedStack = itemStack.clone();
            droppedStack.amount = overflowAmount;
            const spawnLocation = entity.location;
            if (options?.spawnOffset) {
                spawnLocation.x += options.spawnOffset.x;
                spawnLocation.y += options.spawnOffset.y;
                spawnLocation.z += options.spawnOffset.z;
            }
            const itemEntity = entity.dimension.spawnItem(droppedStack, spawnLocation);
            options?.spawnCallback?.(itemEntity);
        }
    }
    inventory.container.addItem(itemStack);
}
/**
 * Removes an item from the inventory of an entity.
 * @param entity - The entity from which to remove the item.
 * @param itemId - The ID of the item to remove.
 * @returns True if the item was successfully removed, false otherwise.
 */
export function removeItemFromInventory(entity, itemId) {
    const inventory = entity.getComponent("inventory");
    const container = inventory?.container;
    if (!container)
        return false;
    for (let slotId = 0; slotId < container.size; slotId++) {
        const slot = container.getSlot(slotId);
        const item = slot.getItem();
        if (item?.typeId === itemId) {
            if (item.amount > 1) {
                item.amount--;
                container.setItem(slotId, item);
            }
            else {
                container.setItem(slotId, undefined);
            }
            return true;
        }
    }
    return false;
}
/**
 * Decreases the durability of the item in the player's hand.
 *
 * @param player - The player whose item durability needs to be decreased.
 * @param options - Optional parameters for decreasing item durability.
 * @returns A boolean indicating whether the item durability was decreased.
 */
// Currently DOESNT have a enchantment checker to see if durability is applied. Is still BETA
export function decreaseItemDurabilityInHand(player, options) {
    const ignoreInCreative = !(options?.ignoreInCreative === false);
    if (ignoreInCreative && isGameMode(player, GameMode.creative))
        return true;
    const item = getItemInSlot(player, EquipmentSlot.Mainhand);
    world.sendMessage(`${item?.getTags()}`);
    const durability = item?.getComponent("minecraft:durability");
    if (item && durability) {
        const chance = durability.getDamageChance();
        if (Math.random() < chance) {
            if (durability.damage === durability.maxDurability) {
                setItemInSlot(player, EquipmentSlot.Mainhand, options?.convertInto ? new ItemStack(options.convertInto, item.amount) : undefined);
                world.playSound(options?.destructionSound || "random.break", player.location);
            }
            else {
                durability.damage++;
                setItemInSlot(player, EquipmentSlot.Mainhand, item);
            }
            return true;
        }
    }
    return false;
}
/**
 * Filters an entity based on the provided options.
 * @param entity - The entity to filter.
 * @param options - The filtering options.
 * @returns A boolean indicating whether the entity passes the filter.
 */
export function filterEntities(entity, options) {
    const entityType = entity.typeId;
    const typeFamilyComponent = entity.getComponent("minecraft:type_family");
    // Check inclusion first
    if (options.include !== "all" && !options.include.includes(entityType)) {
        return false;
    }
    // Check exclusion
    if (options.exclude && options.exclude.includes(entityType)) {
        return false;
    }
    // If the entity has a family component, check family-related conditions
    if (typeFamilyComponent) {
        const familyTypes = typeFamilyComponent.getTypeFamilies();
        // If options.isFamily is specified, ensure the entity belongs to at least one of the families
        if (options.isFamily && !options.isFamily.some((family) => familyTypes.includes(family))) {
            return false;
        }
    }
    // If all checks pass, return true
    return true;
}
