import { Block, Dimension, Entity, ItemStack, system } from "@minecraft/server";
import { blockNeighbors } from "../../../library/blockManager";

/**
 * Evento onTick del componente fluidConverterComponent
 * Addon: Electrical Creativity BP
 * @param {{entity: Entity, block: Block, dimension: Dimension}} event
 */
export const fluidConverterOnTickEvent = ({ entity, block, dimension }) => {
    try {
        const power = block.permutation.getState('nps_ec:power');
        const charged = block.permutation.getState('nps_ec:charged');
        if (power && charged) {
            onCharged(block, dimension);
        } else if (power && !charged) {
            offCharged(block, dimension);
        }
    } catch {
    }
};

/**
 * Función que maneja el evento onTick del componente fluidConverterComponent.
 * Si el bloque no está cargado, busca cubos de agua, lava o leche en los bloques hopper adyacentes.
 * Si encuentra uno, lo elimina y genera un cubo vacío en la posición del bloque.
 * @param {Block} block 
 * @param {Dimension} dimension 
 * @returns 
 */
const offCharged = (block, dimension) => {
    try {
        const { blockNeighborEast,
            blockNeighborWest,
            blockNeighborNorth,
            blockNeighborSouth } = blockNeighbors(block);

        if (blockNeighborEast.typeId === "minecraft:hopper") {
            const result = findBucketInHopper(block, blockNeighborEast, 4, dimension);
            if (result.found) {
                return;
            }
            block = result.block;
        }
        if (blockNeighborWest.typeId === "minecraft:hopper") {
            const result = findBucketInHopper(block, blockNeighborWest, 5, dimension);
            if (result.found) {
                return;
            }
            block = result.block;
        }
        if (blockNeighborNorth.typeId === "minecraft:hopper") {
            const result = findBucketInHopper(block, blockNeighborNorth, 3, dimension);
            if (result.found) {
                return;
            }
            block = result.block;
        }
        if (blockNeighborSouth.typeId === "minecraft:hopper") {
            const result = findBucketInHopper(block, blockNeighborSouth, 2, dimension);
            if (result.found) {
                return;
            }
            block = result.block;
        }
    } catch { }
}

/**
 * Busca un cubo en el bloque hopper adyacente.
 * Si encuentra un cubo de agua, lava o leche, lo elimina y genera un cubo vacío en la posición del bloque.
 * Si no encuentra ninguno, devuelve el bloque original.
 * @param {Block} block 
 * @param {Block} hopper 
 * @param {Number} direction 
 * @param {Dimension} dimension 
 */
const findBucketInHopper = (block, hopper, direction, dimension) => {
    try {
        const locationUp = { x: block.location.x, y: block.location.y + 1, z: block.location.z };
        const facingDirection = hopper.permutation.getState('facing_direction')
        const toggleBit = hopper.permutation.getState('toggle_bit');

        if (facingDirection != direction || toggleBit) {
            return { found: false, block };
        }

        let permutation = block.permutation;

        let done = false;
        const container = hopper.getComponent('minecraft:inventory')?.container;
        if (container) {
            for (let i = 0; i < container.size; i++) {
                const slotItem = container.getItem(i);
                if (slotItem !== undefined) {
                    switch (slotItem.typeId) {
                        case "minecraft:water_bucket":
                            permutation = permutation.withState('nps_ec:type', "water");
                            done = true;
                            break;
                        case "minecraft:lava_bucket":
                            permutation = permutation.withState('nps_ec:type', "lava");
                            done = true;
                            break;
                        case "minecraft:milk_bucket":
                            permutation = permutation.withState('nps_ec:type', "milk");
                            done = true;
                            break;
                        default:
                            continue;
                    }
                } else {
                    continue;
                }

                if (done) {
                    if (slotItem) {
                        container.setItem(i, null);
                        dimension.runCommand(`playsound random.click @a ${block.x} ${block.y} ${block.z}`);
                        dimension.spawnItem(new ItemStack("minecraft:bucket", 1), locationUp);
                        permutation = permutation.withState('nps_ec:charged', true);
                        break;
                    }
                }
            }

            if (done) {
                block.setPermutation(permutation);
                return { found: true, block };
            } else {
                block.setPermutation(permutation);
                return { found: false, block };
            }
        }
    } catch { }
}


/**
 * Función que maneja el evento onTick del componente fluidConverterComponent.
 * Si el bloque está cargado, genera un ítem en la posición del bloque.
 * @param {Block} block 
 * @param {Dimension} dimension 
 */
const onCharged = (block, dimension) => {
    try {
        const locationUp = { x: block.location.x, y: block.location.y + 1, z: block.location.z };

        let permutation = block.permutation;

        if (permutation.getState('nps_ec:state') != 4) {
            permutation = permutation.withState('nps_ec:state', permutation.getState('nps_ec:state') + 1);
        } else {
            if (block.above(1).typeId === "minecraft:chest") {
                const chest = block.above(1);
                const container = chest.getComponent('minecraft:inventory')?.container;

                if (container) {
                    const itemToGenerate = getItemForType(permutation.getState('nps_ec:type'));
                    let itemAdded = false;

                    switch (itemToGenerate.typeId) {
                        case "minecraft:slime":
                            dimension.runCommand(`playsound hit.slime @a ${block.x} ${block.y} ${block.z}`)
                            break;
                        case "minecraft:magma":
                            dimension.runCommand(`playsound mob.magmacube.big @a ${block.x} ${block.y} ${block.z}`)
                            break;
                        case "minecraft:bone_block":
                            dimension.runCommand(`playsound use.bone_block @a ${block.x} ${block.y} ${block.z} 10`)
                            break;
                        default:
                            break;
                    }

                    // Intentar apilar en un stack existente
                    for (let i = 0; i < container.size; i++) {
                        const slotItem = container.getItem(i);
                        if (slotItem && slotItem.typeId === itemToGenerate.typeId && slotItem.amount < 64) {
                            const spaceLeft = 64 - slotItem.amount;
                            const amountToAdd = Math.min(spaceLeft, 1); // Generar 1 ítem por tick
                            slotItem.amount += amountToAdd;
                            container.setItem(i, slotItem);
                            itemAdded = true;
                            break;
                        }
                    }

                    // Si no se pudo apilar, buscar un espacio vacío
                    if (!itemAdded) {
                        for (let i = 0; i < container.size; i++) {
                            if (!container.getItem(i)) {
                                container.setItem(i, new ItemStack(itemToGenerate.typeId, 1));
                                itemAdded = true;
                                break;
                            }
                        }
                    }

                    // Si no hay espacio, generar el ítem en el mundo
                    if (!itemAdded) {
                        dimension.spawnItem(new ItemStack(itemToGenerate.typeId, 1), locationUp);
                    }
                }
            } else {
                // Si no hay un cofre arriba, generar el ítem en el mundo
                const itemToGenerate = getItemForType(permutation.getState('nps_ec:type'));

                switch (itemToGenerate.typeId) {
                    case "minecraft:slime":
                        dimension.runCommand(`playsound hit.slime @a ${block.x} ${block.y} ${block.z}`)
                        break;
                    case "minecraft:magma":
                        dimension.runCommand(`playsound mob.magmacube.big @a ${block.x} ${block.y} ${block.z}`)
                        break;
                    case "minecraft:bone_block":
                        dimension.runCommand(`playsound use.bone_block @a ${block.x} ${block.y} ${block.z} 10`)
                        break;
                    default:
                        break;
                }
                dimension.spawnItem(new ItemStack(itemToGenerate.typeId, 1), locationUp);
            }

            // Reiniciar el estado del bloque
            permutation = permutation.withState('nps_ec:state', 0);
            permutation = permutation.withState('nps_ec:charged', false);
            permutation = permutation.withState('nps_ec:type', "none");
            system.runTimeout(() => {
                dimension.runCommand(`playsound random.click @a ${block.x} ${block.y} ${block.z}`);
            }, 2)
        }
        block.setPermutation(permutation);
    } catch { }
}

/**
 * Obtiene el ítem correspondiente al tipo de fluido.
 * @param {string} type - Tipo de fluido (water, lava, milk).
 * @returns {ItemStack} Ítem correspondiente al tipo.
 */
function getItemForType(type) {
    switch (type) {
        case "water":
            return { typeId: "minecraft:slime" };
        case "lava":
            return { typeId: "minecraft:magma" };
        case "milk":
            return { typeId: "minecraft:bone_block" };
        default:
            return { typeId: "minecraft:air" }; // Tipo por defecto si no coincide
    }
}