import { system, world, ItemStack, MolangVariableMap } from "@minecraft/server";
import * as mcUi from "@minecraft/server-ui";
import * as AxZ from "./APIs/AxZ-API.js";
import { QIDB } from "./APIs/QIDB.js";

const db = new QIDB("vtng_chest");

const secondsToLockChest = 10;

const chestConfig = {
    "vtng_fn:improved_chest": {
        pagesNum: 4,
        fullBlockCollision: true,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:advanced_chest": {
        pagesNum: 9,
        fullBlockCollision: true,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:ultimate_chest": {
        pagesNum: 18,
        fullBlockCollision: true,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:magnet_chest": {
        pagesNum: 1,
        magnetRadius: 5,
        magnetStrength: 0.1,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:improved_magnet_chest": {
        pagesNum: 3,
        magnetRadius: 7,
        magnetStrength: 0.2,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:advanced_magnet_chest": {
        pagesNum: 6,
        magnetRadius: 10,
        magnetStrength: 0.3,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:ultimate_magnet_chest": {
        pagesNum: 9,
        magnetRadius: 13,
        magnetStrength: 0.4,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:locked_chest": {
        pagesNum: 1,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:portal_chest": {
        pagesNum: 1,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:improved_portal_chest": {
        pagesNum: 4,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:advanced_portal_chest": {
        pagesNum: 8,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    },
    "vtng_fn:ultimate_portal_chest": {
        pagesNum: 12,
        classicProfile: { previousButtonSlot: 8, pageNumInfoSlot: 17, nextButtonSlot: 26 },
        pocketProfile: { previousButtonSlot: 24, pageNumInfoSlot: 25, nextButtonSlot: 26 }
    }
};


world.beforeEvents.worldInitialize.subscribe(xZ => {
    xZ.blockComponentRegistry.registerCustomComponent("vtng_fn:chest", {
        onPlace: ({ block, dimension }) => {
            if (!chestConfig[block.typeId]) return console.warn('Baú não configurado!'), dimension.playSound('note.bass', block.location);
            if (dimension.getEntities({ location: block.center(), type: `vtng_fn:chest_inventory`, maxDistance: 0.9 })[0]) return;
        
            const containerEntity = dimension.spawnEntity(`vtng_fn:chest_inventory`, block.bottomCenter());
            containerEntity.setDynamicProperty('vtng_fn:chest_type', block.typeId);
            containerEntity.nameTag = `tile.${block.typeId}.name`;

            const blockRotation = block.permutation.getState('minecraft:cardinal_direction');
            const visualEntity = dimension.spawnEntity(`${block.typeId}_entity`, block.center());
            visualEntity.setProperty('vtng_fn:cardinal_rotation', blockRotation);
            block.setPermutation(block.permutation.withState('vtng_fn:placed', true));

            // Add Placeholder
            if (chestConfig[block.typeId].pagesNum > 1) {
                const chestInfos = chestConfig[block.typeId].classicProfile; if (!chestInfos) return;
                const chestInv = containerEntity?.getComponent('minecraft:inventory').container;
                chestInv.setItem(chestInfos.previousButtonSlot, new ItemStack('vtng_fn:previous_page_button', 1));
                chestInv.setItem(chestInfos.pageNumInfoSlot, new ItemStack('vtng_fn:page_1', 1));
                chestInv.setItem(chestInfos.nextButtonSlot, new ItemStack('vtng_fn:next_page_button', 1));

                if (block.typeId.includes('portal_chest')) savePageItems(containerEntity, getPortalPageId(visualEntity, block.typeId, 1));
            };
        }
    });
});


// Fake Selection System
world.afterEvents.dataDrivenEntityTrigger.subscribe(({entity}) => {
    const block = entity.dimension.getBlock(entity.location); if (block.isAir) return;
    const fakeSelection = block.permutation.getState('vtng_fn:fake_selection');
    const nearestPlayer = entity.dimension.getPlayers({maxDistance: 8, location: block.center(), families: ['player'], closest: 1})[0];
    if (nearestPlayer) {
        let correctViewDirection;
        if (fakeSelection) {
            const chestEntity = nearestPlayer.getEntitiesFromViewDirection({maxDistance: 8, type: 'vtng_fn:chest_inventory'})[0]?.entity;
            if (JSON.stringify(chestEntity?.location || {}) == JSON.stringify(entity.location)) correctViewDirection = true;
        };
        if (!fakeSelection) {
            const chestBlock = nearestPlayer.getBlockFromViewDirection({maxDistance: 8})?.block;
            if (JSON.stringify(chestBlock?.location || {}) == JSON.stringify(block.location)) correctViewDirection = true;
        };

        if (correctViewDirection) {
            if (!nearestPlayer.isSneaking && !fakeSelection) {
                entity.triggerEvent('vtng_fn:add_collision');
                block.setPermutation(block.permutation.withState('vtng_fn:fake_selection', true));
                entity.teleport(block.bottomCenter());
            };
            if (nearestPlayer.isSneaking && fakeSelection) {
                entity.triggerEvent('vtng_fn:remove_collision');
                block.setPermutation(block.permutation.withState('vtng_fn:fake_selection', false));
                entity.teleport(block.center());
            };
            if (!nearestPlayer.isSneaking) entity.dimension.spawnEntity(`vtng_fn:outline_selection_chest${chestConfig[block.typeId].fullBlockCollision ? '_2' : ''}`, block.center());
        };                
    } else if (!fakeSelection) {
        entity.triggerEvent('vtng_fn:add_collision');
        block.setPermutation(block.permutation.withState('vtng_fn:fake_selection', true));
        entity.teleport(block.bottomCenter());
    };

    const hasChestOpen = entity.dimension.getPlayers({maxDistance: 8, location: block.center(), tags: ['vtng_fn:chest_open'], closest: 1})[0];
    if (!hasChestOpen && block.permutation.getState('vtng_fn:is_opened')) {
        block.setPermutation(block.permutation.withState('vtng_fn:is_opened', false));
        const visualEntity = entity.dimension.getEntities({ type: `${block.typeId}_entity`, location: block.center(), maxDistance: 0.25, closest: 1 })[0];
        visualEntity.setProperty('vtng_fn:is_opened', false);
        entity.dimension.playSound('random.chestclosed', entity.location);

        // Salvar os dados quando fechar o baú
        const inMenuPage = entity.getProperty('vtng_fn:in_menu'); 
        if (!inMenuPage && (chestConfig[block.typeId].pagesNum > 1 || block.typeId.includes('portal_chest'))) {
            if (block.typeId.includes('portal_chest')) {
                const firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
                const secondDigit = visualEntity.getProperty('vtng_fn:second_digit');
                const chestType = block.typeId.replace('vtng_fn:', '').replace('_portal_chest', '');

                const openChests = JSON.parse(world.getDynamicProperty('vtng_fn:portal_chest') || '{}');
                delete openChests[`${chestType}_${firstDigit}${secondDigit}`];
                world.setDynamicProperty('vtng_fn:portal_chest', JSON.stringify(openChests));

                savePageItems(entity, getPortalPageId(visualEntity, block.typeId, entity.getProperty('vtng_fn:current_page')));
            } else savePageItems(entity, getPageId(entity.id, entity.getProperty('vtng_fn:current_page')));
        };
    };

    const playersUse = entity.getDynamicProperty('vtng_fn:playersUse');
    if (playersUse != undefined && playersUse != '{}' && !hasChestOpen) entity.setDynamicProperty('vtng_fn:playersUse', undefined);
}, {eventTypes: ['vtng_fn:player_nearby_chest']});


// Drop ao quebrar o baú
world.afterEvents.dataDrivenEntityTrigger.subscribe(({entity}) => {
    const chestId = entity.getDynamicProperty('vtng_fn:chest_type');
    const chestInfos = chestConfig[chestId]; if (!chestInfos) return entity.remove();
    const currentPage = entity.getProperty('vtng_fn:current_page');
    const inMenuPage = entity.getProperty('vtng_fn:in_menu'); 
    const pocketUi = entity.getProperty('vtng_fn:pocket_ui');
    const uiProfile = chestInfos[pocketUi ? 'pocketProfile' : 'classicProfile'];
    const chestInv = entity?.getComponent('minecraft:inventory').container;

    if (chestId.includes('portal_chest')) {
        const visualEntity = entity.dimension.getEntities({ type: `${chestId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
        const firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
        const secondDigit = visualEntity.getProperty('vtng_fn:second_digit');
        const chestType = chestId.replace('vtng_fn:', '').replace('_portal_chest', '');

        const openChests = JSON.parse(world.getDynamicProperty('vtng_fn:portal_chest') || '{}'); 
        if (!openChests[`${chestType}_${firstDigit}${secondDigit}`] && !inMenuPage) {
            savePageItems(entity, getPortalPageId(visualEntity, chestId, currentPage));
        };  
        return entity.remove();
    };

    const buttonSlots = [uiProfile.previousButtonSlot, uiProfile.pageNumInfoSlot, uiProfile.nextButtonSlot];
    if (!inMenuPage) for (let slot = 0; slot < chestInv.size; slot++) {
        if (!buttonSlots.includes(slot) || chestConfig[chestId].pagesNum <= 1) {
            const item = chestInv.getItem(slot);
            if (item) entity.dimension.spawnItem(item, entity.location);
        };
    };

    for (let page = 1; page <= chestInfos.pagesNum; page++) {
        const pageId = `pg_${Math.abs(entity.id)}_${page}`.slice(0, 30);
        if ((page != currentPage || inMenuPage) && db.has(pageId)) {
            const items = db.get(pageId);
            for (let slot = 0; slot < chestInv.size; slot++) {
                if (items[slot]) entity.dimension.spawnItem(items[slot], entity.location);
            };
            db.delete(pageId);
        };
    };
    entity.remove();
}, {eventTypes: ['vtng_fn:destroyed_block_chest']});

// Garante q o tick pare quando a entidade for descarregada e carregada -------- O bug do tick parar deve estar por aqui.
world.afterEvents.entityLoad.subscribe(xZ => {
    if (xZ.entity.typeId != 'vtng_fn:chest_inventory') return;
    const block = xZ.entity.dimension.getBlock(xZ.entity.location); if (block.isAir) return;
    const hasChestOpen = xZ.entity.dimension.getPlayers({maxDistance: 8, location: block.center(), families: ['player'], tags: ['vtng_fn:chest_open'], closest: 1})[0];
    if (!hasChestOpen && block.permutation.getState('vtng_fn:is_opened')) {
        block.setPermutation(block.permutation.withState('vtng_fn:is_opened', false));
        const visualEntity = entity.dimension.getEntities({ type: `${block.typeId}_entity`, location: block.center(), maxDistance: 0.25, closest: 1 })[0];
        visualEntity.setProperty('vtng_fn:is_opened', false);
        entity.dimension.playSound('random.chestclosed', entity.location);
        entity.setDynamicProperty('vtng_fn:playersUse', undefined);
    };
});

// Casos onde NÃO abre o baú
world.beforeEvents.playerInteractWithEntity.subscribe(xZ => {
    const { player, target: entity } = xZ;
    if (entity.typeId != "vtng_fn:chest_inventory") return;
    const block = player.dimension.getBlock(entity.location); if (block.isAir) return;

    const pos1 = player.location;
    const pos2 = entity.location;
    const distance = Math.hypot(pos2.x - pos1.x, pos2.y - (pos1.y + 1), pos2.z - pos1.z);
    
    if (distance >= 4.5 || AxZ.isSolid(block.above())) return xZ.cancel = true;

    const chestId = entity.getDynamicProperty('vtng_fn:chest_type');
    if (chestId.includes('locked_chest')) {
        const password = entity.getDynamicProperty('vtng_fn:password');
        if (!password) {
            system.run(() => { setPassword(player, entity); });
            return xZ.cancel = true;
        };

        const access = JSON.parse(entity.getDynamicProperty('vtng_fn:access') || '{}');
        if (system.currentTick - access[player.id] > secondsToLockChest * 20) delete access[player.id];
        if (!Object.keys(access).includes(player.id)) {
            system.run(() => { 
                entity.setDynamicProperty('vtng_fn:access', JSON.stringify(access));
                enterPassword(player, entity); 
            });
            return xZ.cancel = true;
        };
    };

    if (chestId.includes('portal_chest')) {
        const visualEntity = entity.dimension.getEntities({ type: `${chestId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
        const firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
        const secondDigit = visualEntity.getProperty('vtng_fn:second_digit');
        const chestType = chestId.replace('vtng_fn:', '').replace('_portal_chest', '');

        if (firstDigit == 0 && secondDigit == 0) {
            system.run(() => { setFrequency(player, visualEntity); });
            return xZ.cancel = true;
        };
        
        const openChests = JSON.parse(world.getDynamicProperty('vtng_fn:portal_chest') || '{}');
        if (openChests[`${chestType}_${firstDigit}${secondDigit}`]) {
            system.run(() => { 
                player.playSound('note.bass', { volume: 0.4 });
                player.sendMessage({translate: 'text.vtng_fn.busy_portal_chest' });
            });
            return xZ.cancel = true;
        };
    };
});

// Interação com a entidade, configuração inicial e tag de funcionamento
world.afterEvents.playerInteractWithEntity.subscribe(xZ => {
    const { player, target: entity, itemStack } = xZ;
    const chestId = entity.getDynamicProperty('vtng_fn:chest_type');
    if (!entity?.typeId.includes('vtng_fn') || !entity?.typeId.includes('chest')) return;

    if (!player.hasTag('vtng_fn:configured_ui')) configUiProfile(player);
    if (player.hasTag('vtng_fn:configured_ui') && player.hasTag('vtng_fn:busy_chest') && chestConfig[chestId].pagesNum > 1) {
        return player.sendMessage({translate: 'text.vtng_fn.busy_chest' }), player.playSound('note.bell', {location: player.location});
    };

    if (player.hasTag('vtng_fn:configured_ui') && (!player.hasTag('vtng_fn:busy_chest') || chestConfig[chestId].pagesNum <= 1)) {
        player.addTag('vtng_fn:chest_open');
        const uiProfile = player.getDynamicProperty('vtng_fn:uiProfile');
        const block = entity.dimension.getBlock(entity.location); if (block.isAir) return;

        const pocketUi = block.permutation.getState('vtng_fn:pocket_ui');
        if (uiProfile == 'vtng_fn:uiClassic' && pocketUi) {
            block.setPermutation(block.permutation.withState('vtng_fn:pocket_ui', false));
            entity.setProperty('vtng_fn:pocket_ui', false);

            // Muda a posição dos itens de pocket para classic
            const chestInfos = chestConfig[block.typeId]; if (!chestInfos) return;
            system.run(() => { transferProfileItems(chestInfos.pocketProfile, chestInfos.classicProfile, entity, chestInfos.pagesNum);});
        };
        if (uiProfile == 'vtng_fn:uiPocket' && !pocketUi) {
            block.setPermutation(block.permutation.withState('vtng_fn:pocket_ui', true));
            entity.setProperty('vtng_fn:pocket_ui', true);

            // Muda a posição dos itens de pocket para classic
            const chestInfos = chestConfig[block.typeId]; if (!chestInfos) return;
            system.run(() => { transferProfileItems(chestInfos.classicProfile, chestInfos.pocketProfile, entity, chestInfos.pagesNum); });
        };

        const visualEntity = player.dimension.getEntities({ type: `${block.typeId}_entity`, location: block.center(), maxDistance: 0.25, closest: 1 })[0];
        if (!block.permutation.getState('vtng_fn:is_opened')) {
            block.setPermutation(block.permutation.withState('vtng_fn:is_opened', true));
            visualEntity.setProperty('vtng_fn:is_opened', true);
            entity.dimension.playSound('random.chestopen', entity.location);
            if (chestId.includes('portal_chest') && !entity.getProperty('vtng_fn:in_menu')) {
                loadPageItems(entity, entity.getProperty('vtng_fn:current_page'), uiProfile == 'vtng_fn:uiPocket', true);
            };
        };

        const playersUse = JSON.parse(entity.getDynamicProperty('vtng_fn:playersUse') || '{}');
        system.runTimeout(() => {
            playersUse[player.id] = JSON.stringify(player.getViewDirection());
            entity.setDynamicProperty('vtng_fn:playersUse', JSON.stringify(playersUse));
        }, 5);
    };
});


// Executa enquanto o inventario estiver aberto
world.afterEvents.dataDrivenEntityTrigger.subscribe(({entity}) => {
    const block = entity.dimension.getBlock(entity.location); if (block.isAir) return;
    const pocketUi = block.permutation.getState('vtng_fn:pocket_ui');
    const chestInfos = chestConfig[block.typeId][pocketUi ? 'pocketProfile' : 'classicProfile']; if (!chestInfos) return;
    const isPortalChest = block.typeId.includes('portal_chest');

    const inMenuPage = entity.getProperty('vtng_fn:in_menu'); 
    const currentPage = entity.getProperty('vtng_fn:current_page');
    const chestInv = entity.getComponent('minecraft:inventory').container;

    if (!inMenuPage && chestConfig[block.typeId].pagesNum > 1) {
        const previousButtonItem = chestInv.getItem(chestInfos.previousButtonSlot);
        const nextButtonItem = chestInv.getItem(chestInfos.nextButtonSlot);
        const menuButtonItem = chestInv.getItem(chestInfos.pageNumInfoSlot);

        // Clique dos botões
        if (previousButtonItem?.typeId != 'vtng_fn:previous_page_button') {
            if (previousButtonItem) entity.dimension.spawnItem(previousButtonItem, entity.location);
            chestInv.setItem(chestInfos.previousButtonSlot, new ItemStack(`vtng_fn:previous_page_button`, 1));
            entity.dimension.playSound('random.click', entity.location);
            
            let pageId;
            if (isPortalChest) {
                const visualEntity = entity.dimension.getEntities({ type: `${block.typeId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
                pageId = getPortalPageId(visualEntity, block.typeId, currentPage);
            } else pageId = getPageId(entity.id, currentPage);

            // Ao clicar no botão de voltar
            savePageItems(entity, pageId);
            const newPage = currentPage > 1 ? Math.max(currentPage - 1, 1) : chestConfig[block.typeId].pagesNum;
            entity.setProperty('vtng_fn:current_page', newPage);
            loadPageItems(entity, newPage, pocketUi);
        };
        if (nextButtonItem?.typeId != 'vtng_fn:next_page_button') {
            if (nextButtonItem) entity.dimension.spawnItem(nextButtonItem, entity.location);
            chestInv.setItem(chestInfos.nextButtonSlot, new ItemStack(`vtng_fn:next_page_button`, 1));
            entity.dimension.playSound('random.click', entity.location);

            let pageId;
            if (isPortalChest) {
                const visualEntity = entity.dimension.getEntities({ type: `${block.typeId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
                pageId = getPortalPageId(visualEntity, block.typeId, currentPage);
            } else pageId = getPageId(entity.id, currentPage);

            // Ao clicar no botão de próximo
            const maxPages = chestConfig[block.typeId].pagesNum;
            savePageItems(entity, pageId);
            const newPage = currentPage < maxPages ? Math.min(currentPage + 1, maxPages) : 1;
            entity.setProperty('vtng_fn:current_page', newPage);
            loadPageItems(entity, newPage, pocketUi);
        };
        if (menuButtonItem?.typeId != `vtng_fn:page_${currentPage}`) {
            if (menuButtonItem) entity.dimension.spawnItem(menuButtonItem, entity.location);
            chestInv.setItem(chestInfos.pageNumInfoSlot, new ItemStack(`vtng_fn:page_${currentPage}`, 1));
            entity.dimension.playSound('random.click', entity.location);

            let pageId;
            if (isPortalChest) {
                const visualEntity = entity.dimension.getEntities({ type: `${block.typeId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
                pageId = getPortalPageId(visualEntity, block.typeId, currentPage);
            } else pageId = getPageId(entity.id, currentPage);

            // Ao clicar no botão de menu
            savePageItems(entity, pageId);
            entity.setProperty('vtng_fn:in_menu', true); 
            system.run(() => {
                for (let slot = 0; slot < chestInv.size; slot++) {
                    if (slot < chestConfig[block.typeId].pagesNum) chestInv.setItem(slot, new ItemStack(`vtng_fn:page_${slot + 1}`, 1));
                    else chestInv.setItem(slot);
                };
            });
        };

        // Limpa os botões em posições incorretas
        const buttonSlots = [chestInfos.previousButtonSlot, chestInfos.pageNumInfoSlot, chestInfos.nextButtonSlot];
        for (let slot = 0; slot < chestInv.size; slot++) {
            if (buttonSlots.includes(slot)) continue;
            const item = chestInv.getItem(slot);
            if (item?.typeId == 'vtng_fn:previous_page_button' || item?.typeId == 'vtng_fn:next_page_button' || item?.typeId.startsWith('vtng_fn:page_')) {
                chestInv.setItem(slot);
            };
        };
    } else if (chestConfig[block.typeId].pagesNum > 1) {
        for (let slot = 0; slot < chestInv.size; slot++) {
            if (slot < chestConfig[block.typeId].pagesNum) {
                const item = chestInv.getItem(slot);
                const buttonNum = slot + 1;
                // Ao escolher a pagina
                if (item?.typeId !== `vtng_fn:page_${buttonNum}`) {
                    if (item) entity.dimension.spawnItem(item, entity.location);
                    chestInv.setItem(slot, new ItemStack(`vtng_fn:page_${buttonNum}`, 1));
                    entity.dimension.playSound('random.click', entity.location);

                    entity.setProperty('vtng_fn:in_menu', false);
                    entity.setProperty('vtng_fn:current_page', buttonNum);
                    system.run(() => { loadPageItems(entity, buttonNum, pocketUi); });
                    break;
                };
            } else {
                chestInv.setItem(slot, new ItemStack('vtng_fn:placeholder_invisible', 1));
            };
        };
    };
    
    const playersUse = JSON.parse(entity.getDynamicProperty('vtng_fn:playersUse') || '{}');    
    for (let playerId of Object.keys(playersUse)) {
        const player = world.getEntity(playerId); if (!player) continue;

        // Remove os botões do inventario do jogador
        const playerInv = player.getComponent('minecraft:inventory').container;
        const playerCursor = player.getComponent('minecraft:cursor_inventory');
        const cursorItem = playerCursor.item;
        for (let slot = 0; slot < playerInv.size; slot++) {
            const item = playerInv.getItem(slot);
            if (item?.typeId == 'vtng_fn:previous_page_button' || item?.typeId == 'vtng_fn:next_page_button' || item?.typeId.startsWith('vtng_fn:page_')) {
                playerInv.setItem(slot);
            };
        };
        if (cursorItem?.typeId == 'vtng_fn:previous_page_button' || cursorItem?.typeId == 'vtng_fn:next_page_button' || cursorItem?.typeId.startsWith('vtng_fn:page_')) {
            playerCursor.clear();
        };
        

        // Bloqueia fornalhas para diferentes tipos de UI's
        if (JSON.stringify(player.getViewDirection()) != playersUse[playerId] || player.isSneaking) {
            system.run(() => entity.runCommand('tag @a remove vtng_fn:busy_chest'));
            player.removeTag('vtng_fn:chest_open');
            delete playersUse[playerId];
            entity.setDynamicProperty('vtng_fn:playersUse', JSON.stringify(playersUse));
        };

        if (player.hasTag('vtng_fn:configured_ui')) {
            const uiProfile = player.getDynamicProperty('vtng_fn:uiProfile');
            entity.dimension.getPlayers({maxDistance: 15, location: entity.location, families: ['player']}).forEach(nearbyPlayers => {
                if (!nearbyPlayers.hasTag('vtng_fn:busy_chest') && nearbyPlayers.getDynamicProperty('vtng_fn:uiProfile') != uiProfile) nearbyPlayers.addTag('vtng_fn:busy_chest');
            });
        };
    };
}, {eventTypes: ['vtng_fn:is_opened_chest']});


// Faz a compatibilidade com o hopper a cada 0.4s
world.afterEvents.dataDrivenEntityTrigger.subscribe(({entity}) => {
    const block = entity.dimension.getBlock(entity?.location); if (block?.isAir || !block) return;
    hopperCompatibility(block, entity);
    if (block.typeId.includes('magnet')) magnetChest(block, entity, chestConfig[block.typeId].magnetRadius, entity.dimension, chestConfig[block.typeId].magnetStrength);
}, {eventTypes: ['vtng_fn:hopper_compatibility_chest']});


// Remover Itens de botões caso dropados
world.afterEvents.entitySpawn.subscribe(({ entity }) => {
    if (entity.typeId == "minecraft:item") {
        const itemStack = entity.getComponent('item')?.itemStack;
        if (itemStack?.typeId == 'vtng_fn:previous_page_button' || itemStack?.typeId == 'vtng_fn:next_page_button' 
        || itemStack?.typeId.startsWith('vtng_fn:page_') || itemStack?.typeId == 'vtng_fn:placeholder_invisible'
        || itemStack?.typeId == 'vtng_fn:chimney_collision') {
            entity.remove();
        };
    };
});

world.afterEvents.playerPlaceBlock.subscribe(xZ => {
    const { block, dimension, player } = xZ;
    if (block.typeId.startsWith('vtng_fn:') && block.typeId.includes('locked_chest')) {
        system.run(() => {
            const entity = dimension.getEntities({ type: `vtng_fn:chest_inventory`, location: block.center(), maxDistance: 0.9, closest: 1 })[0];
            setPassword(player, entity);
        });
    };
    if (block.typeId.startsWith('vtng_fn:') && block.typeId.includes('portal_chest')) {
        system.run(() => {
            const visualEntity = dimension.getEntities({ type: `${block.typeId}_entity`, location: block.center(), maxDistance: 0.25, closest: 1 })[0];
            setFrequency(player, visualEntity);
        });
    };
});

world.beforeEvents.playerBreakBlock.subscribe(xZ => {
    const { block, dimension, player } = xZ;
    if (block.typeId.startsWith('vtng_fn:') && block.typeId.includes('locked_chest')) {
        const entity = dimension.getEntities({ type: `vtng_fn:chest_inventory`, location: block.center(), maxDistance: 0.9, closest: 1 })[0];
        const owner = entity.getDynamicProperty('vtng_fn:owner');
        const password = entity.getDynamicProperty('vtng_fn:password');
        const access = JSON.parse(entity.getDynamicProperty('vtng_fn:access') || '{}');
        if (player.id != owner && !Object.keys(access).includes(player.id) && password) {
            system.run(() => { player.playSound('note.bass', { volume: 0.2 }); });
            return xZ.cancel = true;
        };
    };

    if (block.typeId.startsWith('vtng_fn:') && block.typeId.includes('portal_chest')) {
        const visualEntity = dimension.getEntities({ type: `${block.typeId}_entity`, location: block.center(), maxDistance: 0.9, closest: 1 })[0];
        const firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
        const secondDigit = visualEntity.getProperty('vtng_fn:second_digit');
        const chestType = block.typeId.replace('vtng_fn:', '').replace('_portal_chest', '');

        const openChests = JSON.parse(world.getDynamicProperty('vtng_fn:portal_chest') || '{}');
        if (openChests[`${chestType}_${firstDigit}${secondDigit}`]) {
            system.run(() => { 
                player.playSound('note.bass', { volume: 0.4 });
                player.sendMessage({translate: 'text.vtng_fn.portal_chest.dont_destroy' });
            });
            return xZ.cancel = true;
        };
    };
});

world.beforeEvents.playerInteractWithBlock.subscribe(xZ => {
    const { block, player, isFirstEvent } = xZ;
    if (block.typeId.startsWith('vtng_fn:') && block.typeId.includes('portal_chest') && player.isSneaking && isFirstEvent) {
        const visualEntity = block.dimension.getEntities({ type: `${block.typeId}_entity`, location: block.center(), maxDistance: 0.25, closest: 1 })[0];
        if (!visualEntity.getProperty('vtng_fn:is_opened')) {
            system.run(() => { setFrequency(player, visualEntity); });
        } else system.run(() => {
            player.playSound('note.bass', { volume: 0.2 });
            player.sendMessage({translate: 'text.vtng_fn.portal_chest.cannot_change_frequency' })
        });
    };
});



// --------- ÁREA DE FUNÇÕES -------

export function configUiProfile(player) {
    const configForm = new mcUi.ActionFormData();
    configForm.title('vtng_fn.configUi.tittle');
    configForm.body('vtng_fn.configUi.body');
    configForm.button('vtng_fn.configUi.classic', 'textures/vtng/fn/ui/classic_button');
    configForm.button('vtng_fn.configUi.pocket', 'textures/vtng/fn/ui/pocket_button');
    configForm.show(player).then(r => {
        if (r.canceled) return;
        if (r.selection == 0) uiProfileConfirmationForm(player, 'vtng_fn:uiClassic');
        if (r.selection == 1) uiProfileConfirmationForm(player, 'vtng_fn:uiPocket');
    });
};

export function uiProfileConfirmationForm(player, uiProfile) {
    const confirmationForm = new mcUi.ActionFormData();
    confirmationForm.title('vtng_fn.confirmationUi.tittle');
    confirmationForm.body('vtng_fn.confirmationUi.body');
    confirmationForm.button('gui.yes', 'textures/ui/realms_green_check');
    confirmationForm.button('gui.no', 'textures/ui/realms_red_x');
    confirmationForm.show(player).then(r => {
        if (r.canceled || r.selection == 1) return;
        else {
            player.addTag('vtng_fn:configured_ui');
            player.removeTag('vtng_fn:busy_chest')
            player.setDynamicProperty('vtng_fn:uiProfile', uiProfile);
        };
    });
};

function transferProfileItems(sourceProfile, targetProfile, entity, maxPages) {
    const currentPage = entity.getProperty('vtng_fn:current_page');
    const inMenuPage = entity.getProperty('vtng_fn:in_menu'); 
    const entityInv = entity.getComponent('inventory').container;

    if (!inMenuPage) {
        // Copia os itens dos slots de origem
        const sourceButtonSlots = [sourceProfile.previousButtonSlot, sourceProfile.pageNumInfoSlot, sourceProfile.nextButtonSlot];
        const sourceButtonItems = sourceButtonSlots.map(slot => entityInv.getItem(slot));

        // Copia os itens dos slots de alvo
        const targetButtonSlots = [targetProfile.previousButtonSlot, targetProfile.pageNumInfoSlot, targetProfile.nextButtonSlot];
        const targetButtonItems = targetButtonSlots.map(slot => entityInv.getItem(slot));

        // Limpa os slots de origem para evitar sobrescrita
        sourceButtonSlots.forEach((slot, index) => entityInv.setItem(slot, targetButtonItems[index]));
        // Inserir os itens nos slots de destino
        targetButtonSlots.forEach((slot, index) => entityInv.setItem(slot, sourceButtonItems[index]));
    };

    for (let page = 1; page <= maxPages; page++) {
        const pageId = getPageId(entity.id, page);
        if ((page != currentPage || inMenuPage) && db.has(pageId)) {
            const pageItems = db.get(pageId);
            swapSlots(pageItems,
                [sourceProfile.previousButtonSlot, sourceProfile.pageNumInfoSlot, sourceProfile.nextButtonSlot],
                [targetProfile.previousButtonSlot, targetProfile.pageNumInfoSlot, targetProfile.nextButtonSlot]
            );
            db.set(pageId, pageItems);
        };
    };
};

function swapSlots(arr, slotsA, slotsB) {
    const temp = slotsA.map(i => arr[i]);
    slotsA.forEach((slot, idx) => arr[slot] = arr[slotsB[idx]]);
    slotsB.forEach((slot, idx) => arr[slot] = temp[idx]);
};

function getPageId(entityId, pageNum) {
    return `pg_${Math.abs(entityId)}_${pageNum}`.slice(0, 30);
};

function getPortalPageId(visualEntity, chestId, pageNum) {
    const firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
    const secondDigit = visualEntity.getProperty('vtng_fn:second_digit');
    const chestType = chestId.replace('vtng_fn:', '').replace('_portal_chest', '');

    return `${chestType}_${firstDigit}${secondDigit}_${pageNum}`.slice(0, 30);
};

function loadPageItems(entity, pageNum, isPocket, opening) {
    const chestId = entity.getDynamicProperty('vtng_fn:chest_type');
    const entityInv = entity.getComponent('inventory').container;

    let pageId;
    if (chestId.includes('portal_chest')) {
        const visualEntity = entity.dimension.getEntities({ type: `${chestId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
        pageId = getPortalPageId(visualEntity, chestId, pageNum);

        if (opening) {
            const firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
            const secondDigit = visualEntity.getProperty('vtng_fn:second_digit');
            const chestType = chestId.replace('vtng_fn:', '').replace('_portal_chest', '');

            const openChests = JSON.parse(world.getDynamicProperty('vtng_fn:portal_chest') || '{}');
            openChests[`${chestType}_${firstDigit}${secondDigit}`] = true;
            world.setDynamicProperty('vtng_fn:portal_chest', JSON.stringify(openChests));
        };
    } else pageId = getPageId(entity.id, pageNum);
    
    if (db.has(pageId)) {
        const pageItems = db.get(pageId);
        for (let i = 0; i < entityInv.size; i++) {
            entityInv.setItem(i, pageItems[i] ?? undefined);
        };
    } else {
        const chestInfos = chestConfig[chestId];
        const uiProfile = chestInfos[isPocket ? 'pocketProfile' : 'classicProfile'];

        for (let slot = 0; slot < entityInv.size; slot++) {
            if (chestInfos.pagesNum > 1) {
                if (uiProfile.previousButtonSlot == slot) entityInv.setItem(slot, new ItemStack('vtng_fn:previous_page_button', 1));
                else if (uiProfile.pageNumInfoSlot == slot) entityInv.setItem(slot, new ItemStack(`vtng_fn:page_${pageNum}`, 1));
                else if (uiProfile.nextButtonSlot == slot) entityInv.setItem(slot, new ItemStack('vtng_fn:next_page_button', 1));
                else entityInv.setItem(slot);
            } else entityInv.setItem(slot);
        };
    };
};

function savePageItems(entity, pageId) {
    const entityInv = entity.getComponent('inventory').container;
    
    const items = [];
    for (let i = 0; i < entityInv.size; i++) {
        items[i] = entityInv.getItem(i);   
    };
    db.set(pageId, items);
};

function hopperCompatibility(block, entity) {
    const pocketUi = block.permutation.getState('vtng_fn:pocket_ui');
    const chestInfos = chestConfig[block.typeId]; if (!chestInfos) return;
    const uiProfile = chestInfos[pocketUi ? 'pocketProfile' : 'classicProfile'];
    const currentPage = entity.getProperty('vtng_fn:current_page');
    const inMenuPage = entity.getProperty('vtng_fn:in_menu'); 
    const entityInv = entity.getComponent('inventory').container;
    const isPortalChest = block.typeId.includes('portal_chest');
    const chestType = block.typeId.replace('vtng_fn:', '').replace('_portal_chest', '');

    let visualEntity, firstDigit, secondDigit;
    if (isPortalChest) {
        visualEntity = entity.dimension.getEntities({ type: `${block.typeId}_entity`, location: entity.location, maxDistance: 0.9, closest: 1 })[0];
        firstDigit = visualEntity.getProperty('vtng_fn:first_digit');
        secondDigit = visualEntity.getProperty('vtng_fn:second_digit');

        const openChests = JSON.parse(world.getDynamicProperty('vtng_fn:portal_chest') || '{}');
        if (openChests[`${chestType}_${firstDigit}${secondDigit}`]) return;
    };

    const allFaces = ['north', 'south', 'east', 'west', 'above', 'below']; 
    const hopperRot = { 'north': 3, 'south': 2, 'east': 4, 'west': 5, 'above': 0 };
    mainFor: for (let face of allFaces) {
        const hopperBlock = block[face](); if (hopperBlock?.typeId != 'minecraft:hopper') continue;

        if (hopperBlock.permutation.getState('facing_direction') == hopperRot[face] || face == 'below') {
            const hopperInv = hopperBlock.getComponent('minecraft:inventory')?.container; if (!hopperInv) continue;
            if (['above', 'north', 'south', 'east', 'west'].includes(face)) {
                for (let hopperSlot = 0; hopperSlot < hopperInv.size; hopperSlot++) {
                    const hopperItem = hopperInv.getItem(hopperSlot); if (!hopperItem) continue;

                    if (!inMenuPage && !isPortalChest) {
                        for (let chestSlot = 0; chestSlot < entityInv.size; chestSlot++) {
                            const chestItem = entityInv.getItem(chestSlot);
                            if (!chestItem) {
                                hopperInv.setItem(hopperSlot, hopperItem.amount > 1 ? new ItemStack(hopperItem.typeId, hopperItem.amount - 1) : undefined);
                                entityInv.addItem(hopperItem.amount > 1 ? new ItemStack(hopperItem.typeId, 1) : hopperItem);
                                continue mainFor;
                            } else if (chestItem.typeId === hopperItem.typeId && chestItem.amount < 64) {
                                hopperInv.setItem(hopperSlot, hopperItem.amount > 1 ? new ItemStack(hopperItem.typeId, hopperItem.amount - 1) : undefined);
                                entityInv.setItem(chestSlot, new ItemStack(chestItem.typeId, chestItem.amount + 1));
                                continue mainFor;
                            };
                        };
                    };

                    for (let page = 1; page <= chestInfos.pagesNum; page++) {
                        let pageId = isPortalChest ? getPortalPageId(visualEntity, block.typeId, page) : getPageId(entity.id, page);

                        if ((page != currentPage || inMenuPage || isPortalChest) && db.has(pageId)) {
                            const pageItems = db.get(pageId);

                            for (let chestSlot = 0; chestSlot < entityInv.size; chestSlot++) {
                                const pageItem = pageItems[chestSlot];
                                if (!pageItem) {
                                    hopperInv.setItem(hopperSlot, hopperItem.amount > 1 ? new ItemStack(hopperItem.typeId, hopperItem.amount - 1) : undefined);
                                    pageItems[chestSlot] = hopperItem.amount > 1 ? new ItemStack(hopperItem.typeId, 1) : hopperItem;
                                    continue mainFor;
                                } else if (pageItem.typeId === hopperItem.typeId && pageItem.amount < 64) {
                                    hopperInv.setItem(hopperSlot, hopperItem.amount > 1 ? new ItemStack(hopperItem.typeId, hopperItem.amount - 1) : undefined);
                                    pageItems[chestSlot] = new ItemStack(pageItem.typeId, pageItem.amount + 1);
                                    continue mainFor;
                                };
                            };
                        };
                    };
                };
            };
            if (face === 'below') {
                const buttonSlots = [uiProfile.previousButtonSlot, uiProfile.pageNumInfoSlot, uiProfile.nextButtonSlot];

                if (!inMenuPage && !isPortalChest) {
                    for (let chestSlot = 0; chestSlot < entityInv.size; chestSlot++) {
                        if (buttonSlots.includes(chestSlot) && chestInfos.pagesNum > 1) continue;
                        const pageItem = entityInv.getItem(chestSlot); if (!pageItem) continue;

                        for (let hopperSlot = 0; hopperSlot < hopperInv.size; hopperSlot++) {
                            const hopperItem = hopperInv.getItem(hopperSlot);
                            if (!hopperItem) {
                                entityInv.setItem(chestSlot, pageItem.amount > 1 ? new ItemStack(pageItem.typeId, pageItem.amount - 1) : undefined);
                                hopperInv.addItem(pageItem.amount > 1 ? new ItemStack(pageItem.typeId, 1) : pageItem);
                                continue mainFor;
                            } else if (hopperItem.typeId === pageItem.typeId && hopperItem.amount < 64) {
                                entityInv.setItem(chestSlot, pageItem.amount > 1 ? new ItemStack(pageItem.typeId, pageItem.amount - 1) : undefined);
                                hopperInv.setItem(hopperSlot, new ItemStack(hopperItem.typeId, hopperItem.amount + 1));
                                continue mainFor;
                            };
                        };
                    };
                };

                for (let page = 1; page <= chestInfos.pagesNum; page++) {
                    let pageId = isPortalChest ? getPortalPageId(visualEntity, block.typeId, page) : getPageId(entity.id, page);
                    if ((page != currentPage || inMenuPage || isPortalChest) && db.has(pageId)) {
                        const pageItems = db.get(pageId);
                        
                        for (let chestSlot = 0; chestSlot < entityInv.size; chestSlot++) {
                            if (buttonSlots.includes(chestSlot) && chestInfos.pagesNum > 1) continue;
                            const pageItem = pageItems[chestSlot]; if (!pageItem) continue;

                            for (let hopperSlot = 0; hopperSlot < hopperInv.size; hopperSlot++) {
                                const hopperItem = hopperInv.getItem(hopperSlot);
                                if (!hopperItem) {
                                    pageItems[chestSlot] = pageItem.amount > 1 ? new ItemStack(pageItem.typeId, pageItem.amount-1) : undefined;
                                    hopperInv.addItem(pageItem.amount > 1 ? new ItemStack(pageItem.typeId, 1) : pageItem);
                                    continue mainFor;
                                } else if (hopperItem.typeId === pageItem.typeId && hopperItem.amount < 64) {
                                    pageItems[chestSlot] = pageItem.amount > 1 ? new ItemStack(pageItem.typeId, pageItem.amount-1) : undefined;
                                    hopperInv.setItem(hopperSlot, new ItemStack(hopperItem.typeId, hopperItem.amount + 1));
                                    continue mainFor;
                                };
                            };
                        };
                    };
                };
            };
        };
    };
};



function magnetChest(block, entity, radius, dimension, force = 0.1) {
    const blockCenter = block.center();
    
    const itemsInRadius = dimension.getEntities({ type: "minecraft:item", location: blockCenter, maxDistance: radius });
    let nearestItems = [];
    for (const item of itemsInRadius) {
        // Obtém posição do item
        const pos = item.location;
        // Calcula direção normalizada do item até o bloco
        let dx = blockCenter.x - pos.x;
        let dy = blockCenter.y - pos.y;
        let dz = blockCenter.z - pos.z;
        const dist = Math.sqrt(dx*dx + dy*dy + dz*dz) || 1;
        if (dist < 1.25) nearestItems.push(item);
        dx /= dist; dy /= dist; dz /= dist;
        item.applyImpulse({ x: dx * force, y: dy * force, z: dz * force });
    };

    if (nearestItems.length == 0) return;

    const pocketUi = block.permutation.getState('vtng_fn:pocket_ui');
    const chestInfos = chestConfig[block.typeId]; if (!chestInfos) return;
    const uiProfile = chestInfos[pocketUi ? 'pocketProfile' : 'classicProfile'];
    const currentPage = entity.getProperty('vtng_fn:current_page');
    const inMenuPage = entity.getProperty('vtng_fn:in_menu'); 
    const entityInv = entity.getComponent('inventory').container;

    mainFor: for (const itemEntity of nearestItems) {
        const item = itemEntity.getComponent('minecraft:item').itemStack;

        if (!inMenuPage) {
            for (let chestSlot = 0; chestSlot < entityInv.size; chestSlot++) {
                const chestItem = entityInv.getItem(chestSlot);
                if (!chestItem) {
                    entityInv.addItem(item);
                    itemEntity?.remove();
                    continue mainFor;
                } else if (chestItem.typeId === item.typeId && chestItem.amount < 64) {
                    entityInv.setItem(chestSlot, new ItemStack(chestItem.typeId, Math.min(chestItem.amount + item.amount, 64)));
                    if (chestItem.amount + item.amount > 64) itemEntity.dimension.spawnItem(new ItemStack(chestItem.typeId, (chestItem.amount + item.amount) - 64), itemEntity.location);
                    itemEntity?.remove();
                    continue mainFor;
                };
            };
        };

        for (let page = 1; page <= chestInfos.pagesNum; page++) {
            const pageId = getPageId(entity.id, page);
            if ((page != currentPage || inMenuPage) && db.has(pageId)) {
                const pageItems = db.get(pageId);

                for (let chestSlot = 0; chestSlot < entityInv.size; chestSlot++) {
                    const pageItem = pageItems[chestSlot];
                    if (!pageItem) {
                        pageItems[chestSlot] = item;
                        itemEntity?.remove();
                        continue mainFor;
                    } else if (pageItem.typeId === item.typeId && pageItem.amount < 64) {
                        pageItems[chestSlot] = new ItemStack(pageItem.typeId, Math.min(pageItem.amount + item.amount, 64));
                        if (pageItem.amount + item.amount > 64) itemEntity.dimension.spawnItem(new ItemStack(pageItem.typeId, (pageItem.amount + item.amount) - 64), itemEntity.location);
                        itemEntity?.remove();
                        continue mainFor;
                    };
                };
            };
        };
    };
};

function setPassword(player, entity, error) {
    player.playSound('note.bell', { volume: 0.6 });
    const formPassword = new mcUi.ModalFormData();
    formPassword.title('vtng_fn.locked_chest.setPassword.title');
    formPassword.textField(`${error ? 'vtng_fn.locked_chest.setPassword.text_error' : 'vtng_fn.locked_chest.setPassword.text'}`, 'vtng_fn.locked_chest.password.example');
    formPassword.show(player).then(r => {
        if (r.canceled) return;
        const password = r.formValues[0];
        if (password.length >= 3 && !/[^A-Za-z0-9]/.test(password)) {
            entity.setDynamicProperty('vtng_fn:password', password);
            entity.setDynamicProperty('vtng_fn:owner', player.id);
            player.playSound('open_trapdoor.copper', { pitch: 1.25 });
            const access = JSON.parse(entity.getDynamicProperty('vtng_fn:access') || '{}');
            access[player.id] = system.currentTick;
            entity.setDynamicProperty('vtng_fn:access', JSON.stringify(access));
        } else {
            player.playSound('note.bass', { volume: 0.4 });
            return setPassword(player, entity, true);
        }; 
    });
};

function enterPassword(player, entity, error) {
    player.playSound('note.bell', { volume: 0.6 });
    const password = entity.getDynamicProperty('vtng_fn:password');

    const formPassword = new mcUi.ModalFormData();
    formPassword.title('vtng_fn.locked_chest.enterPassword.title');
    formPassword.textField(`${error ? 'vtng_fn.locked_chest.enterPassword.text_error' : 'vtng_fn.locked_chest.enterPassword.text'}`, 'vtng_fn.locked_chest.password.example');
    formPassword.show(player).then(r => {
        if (r.canceled) return;
        if (password == r.formValues[0]) {
            player.playSound('open_trapdoor.copper', { pitch: 1.25 });
            const access = JSON.parse(entity.getDynamicProperty('vtng_fn:access') || '{}');
            access[player.id] = system.currentTick;
            entity.setDynamicProperty('vtng_fn:access', JSON.stringify(access));
        } else {
            player.playSound('note.bass', { volume: 0.4 });
            return enterPassword(player, entity, true);
        }; 
    });
};

function setFrequency(player, entity) {
    player.playSound('note.bell', { volume: 0.4, pitch: 0.65 });
    const firstDigit = entity.getProperty('vtng_fn:first_digit');
    const secondDigit = entity.getProperty('vtng_fn:second_digit');

    const configForm = new mcUi.ModalFormData();
    configForm.title('vtng_fn.portal_chest.setFrequency.title');
    configForm.slider({ translate: 'vtng_fn.portal_chest.setFrequency.select' }, 1, 99, 1, firstDigit + secondDigit == 0 ? 1 : Number(`${firstDigit}${secondDigit}`));
    configForm.show(player).then(r => {
        if (r.canceled) return;
        player.playSound('block.end_portal_frame.fill', { pitch: 0.85 });
        const digits = String(Math.abs(r.formValues[0]));
        const firstDigit = digits.length >= 2 ? digits[digits.length - 2] : 0;
        const secondDigit = digits[digits.length - 1];
        entity.setProperty('vtng_fn:first_digit', Number(firstDigit));
        entity.setProperty('vtng_fn:second_digit', Number(secondDigit));
    });
};