import { BlockPermutation, EquipmentSlot, ItemStack, world, } from "@minecraft/server";
import { addItemToInventory, decreaseItemAmountInHand, getItemInSlot, setItemInSlot, } from "../../helper/utils";
import { namespace } from "../../../config/_config";
export class TransformBlock {
    constructor(config) {
        this.id = config.id;
        this.transforms = config.transforms; // Assign the transforms array
    }
    static registerBehavior(config) {
        const block = new TransformBlock(config);
        this.register(block);
    }
    static register(block) {
        TransformBlock.blocks.push(block);
    }
    static initialize() {
        world.beforeEvents.worldInitialize.subscribe((event) => {
            event.blockComponentRegistry.registerCustomComponent(`${namespace}:transform_block`, {
                onPlayerInteract: (event) => {
                    TransformBlock.transformBlock(event);
                },
            });
        });
    }
    static transformBlock(event) {
        const { block, player } = event;
        if (!block || !player)
            return;
        const transformBlock = TransformBlock.getBlockByIdentifier(block.typeId);
        if (!transformBlock)
            return;
        const playerItem = getItemInSlot(player, EquipmentSlot.Mainhand)?.typeId;
        for (const option of transformBlock.transforms) {
            // Check if the block's current state matches the required "from" state, if any
            if (option.state) {
                if (block.permutation.getState(option.state.state) !== option.state.value) {
                    continue;
                }
            }
            // Correct item check logic:
            if ((option.item === "hand" && playerItem !== undefined) || // If item is "hand", player must have an empty hand
                (option.item !== "hand" && option.item !== playerItem) // If item is not "hand", it must match the player's item
            ) {
                continue; // Skip this transformation
            }
            // Initialize a variable for the new permutation
            let newPermutation;
            // Perform the block transformation
            if (option.transformTo.id === block.typeId) {
                // Block type is the same, transfer existing states
                const existingPermutation = block.permutation;
                newPermutation = BlockPermutation.resolve(block.typeId); // Create a new permutation for the same block type
                // Transfer existing states from the current permutation to the new permutation
                for (const [stateKey, stateValue] of Object.entries(existingPermutation.getAllStates())) {
                    newPermutation = newPermutation.withState(stateKey, stateValue);
                }
            }
            else {
                // Block type is different, use the new block type directly
                newPermutation = BlockPermutation.resolve(option.transformTo.id);
            }
            // Apply new states, if specified
            if (option.transformTo.states) {
                for (const state of option.transformTo.states) {
                    newPermutation = newPermutation.withState(state.state, state.value); // Correctly apply each state to the permutation
                }
            }
            // Set the modified permutation back to the block
            block.setPermutation(newPermutation);
            const location = {
                x: block.location.x + 0.5,
                y: block.location.y + 0.5,
                z: block.location.z + 0.5,
            };
            // Play the sound if specified
            if (option.sound) {
                block.dimension.playSound(option.sound, location);
            }
            // Spawn the particle if specified
            if (option.particle) {
                block.dimension.spawnParticle(option.particle, location);
            }
            // Handle item taking (optional based on `takeItem`)
            if (option.item && option.item !== "hand" && option.takeItem !== false) {
                // Default is to take the item unless `takeItem` is explicitly set to `false`
                decreaseItemAmountInHand(player, 1, true);
            }
            // Handle receiving item
            if (option.receiveItem) {
                addItemToInventory(player, new ItemStack(option.receiveItem));
            }
            if (option.transformItem) {
                const item = getItemInSlot(player, EquipmentSlot.Mainhand);
                if (!item) {
                    setItemInSlot(player, EquipmentSlot.Mainhand, new ItemStack(option.transformItem));
                }
                else {
                    addItemToInventory(player, new ItemStack(option.transformItem));
                }
            }
            return; // Exit after transformation
        }
    }
    static getBlockByIdentifier(identifier) {
        return TransformBlock.blocks.find((block) => block.id === identifier);
    }
}
TransformBlock.blocks = [];
