import { BlockPermutation, BlockTypes, EquipmentSlot, ItemLockMode, system, world } from "@minecraft/server";
import { Belt, parseItem, serializeItem, unlockItems } from "./libraries/Belt";
import { afterEvents, LigthLevel, sleep, Vector } from "./libraries/utils";
const TagBreakables = {
    'is_shovel': ['dirt', 'sand', 'gravel', 'grass', 'snow', 'fertilize_area'],
    'is_pickaxe': ['stone', 'metal', 'mob_spawner', 'rail', 'pick_diggable'],
    'is_axe': ['wood', 'pumpkin', 'text_sign', 'log'],
    'is_hoe': ['crop'],
};
const TypeBreakables = {
    'is_sword': ['minecraft:web'],
    'is_shovel': ['snow', 'minecraft:clay'],
    'is_hoe': ['minecraft:hay_block', 'leaves'],
    'is_axe': ['minecraft:chest', 'bamboo', 'melon_block', '_table', '_stem'],
    'is_pickaxe': ['minecraft:ancient_debris', '_ore', 'netherite', 'minecraft:ender_chest', '_nylium'],
};
const SpecificTools = {
    'minecraft:shears': ['wool', 'vine', 'leaves'],
};
const toolRegex = /(_\b(pickaxe|axe|sword|hoe|shovel)\b)|(shears)$/;
afterEvents.entityHitBlock.subscribe(({ damagingEntity: player, hitBlock: block }) => {
    if (!player.isPlayer() || player.isSneaking || block.isAir || block.isLiquid)
        return;
    const equippable = player.equippable;
    const hand = equippable.getEquipment(EquipmentSlot.Mainhand);
    if (!hand)
        return;
    const itemTags = hand.getTags();
    if (!itemTags.includes('minecraft:is_tool') && !itemTags.includes('minecraft:is_trident') && !SpecificTools[hand.typeId] && !hand.typeId.match(toolRegex))
        return;
    const blockTags = block.getTags();
    if (Object.entries(TypeBreakables).some(([a, b]) => itemTags.some(t => t.match(a)) && b.some(t => block.typeId.match(t))) ||
        Object.entries(TagBreakables).some(([a, b]) => itemTags.some(t => t.match(a)) && b.some(t => blockTags.some(t_ => t_.match(t)))) ||
        SpecificTools[hand.typeId]?.some(t => block.typeId.match(t)))
        return;
    const handIsPick = itemTags.includes('minecraft:is_pickaxe') || hand.typeId.endsWith('_pickaxe');
    const inv = player.inventory.container;
    let pickaxe;
    for (let i = 0; i < inv.size; i++) {
        if (i === player.selectedSlotIndex)
            continue;
        const slot = inv.getSlot(i);
        if (!slot.hasItem() || slot.typeId !== 'vtng_rt:tool_belt')
            continue;
        const belt = new Belt(slot);
        const data = belt.data;
        for (let j = 0; j < data.length; j++) {
            const item = parseItem(data[j]);
            const itemTags = item.getTags();
            if (!itemTags.includes('minecraft:is_tool') && !item.typeId.match(toolRegex))
                continue;
            const currentIsValid = (Object.entries(TypeBreakables).some(([a, b]) => itemTags.some(t => t.match(a)) && b.some(t => block.typeId.match(t))) ||
                Object.entries(TagBreakables).some(([a, b]) => itemTags.some(t => t.match(a)) && b.some(t => blockTags.some(t_ => t_.match(t)))) ||
                SpecificTools[item.typeId]?.some(t => block.typeId.match(t)));
            const itemIsPick = itemTags.includes('minecraft:is_pickaxe') || hand.typeId.endsWith('_pickaxe');
            if (!handIsPick && itemIsPick && !pickaxe)
                pickaxe = { belt, item, slot: j };
            if (!currentIsValid)
                continue;
            equippable.setEquipment(EquipmentSlot.Mainhand, item);
            player.playSound('armor.equip_generic');
            data[j] = { slot: j, ...serializeItem(hand) };
            belt.data = data;
            return;
        }
    }
    if (!pickaxe)
        return;
    const data = pickaxe.belt.data;
    equippable.setEquipment(EquipmentSlot.Mainhand, pickaxe.item);
    player.playSound('armor.equip_generic');
    data[pickaxe.slot] = { slot: pickaxe.slot, ...serializeItem(hand) };
    pickaxe.belt.data = data;
});
afterEvents.entityHitEntity.subscribe(({ damagingEntity: player, hitEntity: target }) => {
    if (!player.isPlayer() || player.isSneaking)
        return;
    const family = target.getComponent('type_family');
    if (!family || family.hasTypeFamily('inanimate'))
        return;
    const equippable = player.equippable;
    const hand = equippable.getEquipment(EquipmentSlot.Mainhand);
    if (!hand)
        return;
    const itemTags = hand?.getTags();
    if ((!itemTags.includes('minecraft:is_tool') && !hand.typeId.match(toolRegex)) || itemTags.some(t => t.match(/is_(sword|trident)/)))
        return;
    const inv = player.inventory.container;
    for (let i = 0; i < inv.size; i++) {
        if (i === player.selectedSlotIndex)
            continue;
        const slot = inv.getSlot(i);
        if (!slot.hasItem() || slot.typeId !== 'vtng_rt:tool_belt')
            continue;
        const belt = new Belt(slot);
        const data = belt.data;
        for (let j = 0; j < data.length; j++) {
            const item = parseItem(data[j]);
            if (!item?.getTags().some(t => t.match(/is_(sword|trident)/)) && !item?.typeId.endsWith('_sword'))
                continue;
            equippable.setEquipment(EquipmentSlot.Mainhand, item);
            player.playSound('armor.equip_generic');
            data[j] = { slot: j, ...serializeItem(hand) };
            belt.data = data;
            return;
        }
    }
});
afterEvents.playerPlaceBlock.subscribe(({ player, block }) => {
    const hand = player.equippable.getEquipmentSlot(EquipmentSlot.Mainhand);
    if (hand.hasItem() && hand.typeId === block.typeId)
        return;
    const inv = player.inventory.container;
    for (let i = 0; i < inv.size; i++) {
        const slot = inv.getSlot(i);
        if (!slot.hasItem() || slot.typeId !== 'vtng_rt:tool_belt')
            continue;
        const belt = new Belt(slot);
        const data = belt.data;
        for (let j = 0; j < data.length; j++) {
            const item = parseItem(data[j]);
            if (item?.typeId !== block.typeId)
                continue;
            hand.setItem(item);
            player.playSound('armor.equip_generic');
            data.splice(j, 1);
            belt.data = data;
            return;
        }
    }
});
const Belts = new Map();
system.runInterval(async () => {
    const players = world.getPlayers();
    for (const player of players) {
        if (!player.isValid())
            continue;
        const { dimension, location, id: ID } = player;
        const spawned = dimension.getEntities({ type: 'vtng_rt:tool_belt_container', tags: [`tool_belt:${ID}`] })[0];
        if (spawned && dimension.getBlock(location)?.typeId.match('portal')) {
            if (spawned.isValid())
                spawned.remove();
            continue;
        }
        const equippable = player.equippable;
        const hand = equippable.getEquipmentSlot(EquipmentSlot.Mainhand);
        if (!hand.hasItem() || hand?.typeId !== 'vtng_rt:tool_belt') {
            if (spawned?.isValid())
                spawned.remove();
            unlockItems(player, 'vtng_rt:tool_belt');
            Belts.delete(ID);
            continue;
        }
        hand.lockMode = ItemLockMode.slot;
        let container = spawned ?? setupContainer(player, hand.nameTag);
        const head = player.getHeadLocation();
        container.teleport(head, { dimension });
        let belt = Belts.get(ID);
        if (!belt) {
            belt = new Belt(hand);
            if (belt.data.length)
                belt.loadIventory(container.inventory?.container);
        }
        if (belt.id !== hand.getDynamicProperty('ID')) {
            belt.slot = hand;
            belt = new Belt(hand);
            container.remove();
            container = setupContainer(player, hand.nameTag);
            if (belt.data.length)
                belt.loadIventory(container.inventory?.container);
        }
        belt.saveInventory(container.inventory?.container);
        Belts.set(ID, belt);
    }
});
const isOldVersion = !BlockTypes.get('minecraft:light_block_0');
function SetLight(player, getLocation, level = 15) {
    const dimension = player.dimension;
    const location = getLocation();
    const block = player.dimension.getBlock(location);
    const LightBlock = isOldVersion ?
        BlockPermutation.resolve('minecraft:light_block', { block_light_level: level })
        : BlockPermutation.resolve('minecraft:light_block_' + level);
    if ((!block.isAir && !block.typeId.match('minecraft:light_block_')) || block.matches(LightBlock.type.id))
        return;
    const pos = JSON.stringify({
        owner: player.id,
        pos: location,
        dimensionID: dimension.id
    });
    const ID = 'DL:' + pos;
    world.setDynamicProperty(ID, pos);
    block.setPermutation(LightBlock);
    async function OldState() {
        await sleep();
        if (Vector.equals(getLocation(), location) && Light.has(player))
            return OldState();
        world.setDynamicProperty(ID);
        if (block.matches(LightBlock.type.id))
            block.setType('minecraft:air');
    }
    OldState();
}
world.getDynamicPropertyIds().forEach(function NoLight(ID) {
    if (!ID.startsWith('DL:'))
        return;
    try {
        const { pos, dimensionID } = JSON.parse(world.getDynamicProperty(ID));
        const block = world.getDimension(dimensionID).getBlock(pos);
        if (!block)
            return system.run(() => NoLight(ID));
        if (block?.typeId.startsWith('minecraft:light_block'))
            block.setType('minecraft:air');
        world.setDynamicProperty(ID);
    }
    catch { }
});
function setupContainer(player, name) {
    const BPContainer = player.dimension.spawnEntity('vtng_rt:tool_belt_container', player.getHeadLocation());
    BPContainer.addTag(`tool_belt:${player.id}`);
    BPContainer.nameTag = name ?? 'Tool Belt';
    return BPContainer;
}
