import { world, system, BlockPermutation, ItemStack } from "@minecraft/server";

export class OreRefinerComponent {
    constructor() {
        this.onTick = this.onTick.bind(this);
        this.onPlayerInteract = this.onPlayerInteract.bind(this);
        this.beforeOnPlayerPlace = this.beforeOnPlayerPlace.bind(this);
        this.onPlayerDestroy = this.onPlayerDestroy.bind(this);

        this.MINECRAFT_ORES_LOOT = [
            "minecraft:coal",
            "minecraft:copper_ingot",
            "minecraft:iron_ingot",
            "minecraft:gold_ingot",
            "minecraft:redstone",
            "minecraft:lapis_lazuli",
            "minecraft:emerald",
            "minecraft:diamond",
            "minecraft:netherite_scrap"
        ];

        this.ORE_CREDIT = [
            1,    // coal
            6,    // copper
            8,    // iron
            12,    // gold
            2,    // redstone
            2,    // lapis
            12,    // emerald
            128,   // diamond
            2048// ancient debris
        ];

        this.dropQueue = []; // Queue to manage item drops
    }

    onPlayerInteract(e) {
        const block = e.block;
        const player = e.player;
        let selectedSlot = player.selectedSlotIndex;
        let handItem = player.getComponent("inventory").container.getItem(selectedSlot);
        if (!handItem) return

        if (this.MINECRAFT_ORES_LOOT.includes(handItem?.typeId)) {
            let oreIndex = this.MINECRAFT_ORES_LOOT.indexOf(handItem.typeId);
            block.setPermutation(block.permutation.withState('pb_red:ore_result', oreIndex));
            block.dimension.runCommand(`playsound random.orb @a ${block.location.x} ${block.location.y} ${block.location.z}`);
        }
        if (handItem.typeId == "pb_red:redstone_wrench") {
            const AllStates = [
                { state: "minecraft:cardinal_direction", values: ["north", "east", "south", "west"] },
                { state: "minecraft:facing_direction", values: ["north", "east", "south", "west", "up", "down"] }
            ]

            AllStates.some((stateObj) => {
                const currentState = block.permutation.getState(stateObj.state);

                if (currentState !== undefined && currentState !== null) {
                    const stateValues = stateObj.values;
                    const currentStateIndex = stateValues.indexOf(currentState);
                    const nextState = currentStateIndex >= stateValues.length - 1 ? stateValues[0] : stateValues[currentStateIndex + 1];

                    block.setPermutation(block.permutation.withState(stateObj.state, nextState));
                    block.dimension.runCommand(`playsound vr.stutterturn @a ${block.location.x} ${block.location.y} ${block.location.z}`)
                }
            });
        }

        // Update the level state
        this.updateLevelState(block);
    }

    getBlockCredits(block) {
        const key = `pb_red:ore_refiner_credits:x_${block.location.x}:y_${block.location.y}:z_${block.location.z}:dim_${block.dimension.id.replace("minecraft:", "")}`;
        return world.getDynamicProperty(key) || 0;
    }

    setBlockCredits(block, credits) {
        const key = `pb_red:ore_refiner_credits:x_${block.location.x}:y_${block.location.y}:z_${block.location.z}:dim_${block.dimension.id.replace("minecraft:", "")}`;
        world.setDynamicProperty(key, credits);
    }

    updateLevelState(block) {
        const oreResultIndex = block.permutation.getState('pb_red:ore_result');
        const refinedOreCredit = this.ORE_CREDIT[oreResultIndex];
        const credits = this.getBlockCredits(block);
        const newLevel = Math.floor((credits / refinedOreCredit) * 10);
        block.setPermutation(block.permutation.withState('pb_red:level', Math.min(newLevel, 10)));
    }

    async processDropQueue(block) {
        while (this.dropQueue.length > 0) {
            const { itemStack, location } = this.dropQueue.shift();
            block.dimension.spawnItem(itemStack, location).teleport({
                x: location.x,
                y: location.y - 0.5,
                z: location.z,
            });
            block.dimension.runCommand(`playsound random.pop @a ${location.x} ${location.y} ${location.z} 0.5`);

            // Wait 0.5 seconds before dropping the next item
            await new Promise(resolve => system.runTimeout(resolve, 20));
        }
    }

    beforeOnPlayerPlace(e) {
        const block = e.block;
        const player = e.player;

        this.setBlockCredits(block, 0);

    }

    onPlayerDestroy(e) {
        const block = e.block;

        system.runTimeout(() => {
            try {
                if (block) {
                    // console.warn("break")
                    let currentCredits = this.getBlockCredits(block);

                    block.dimension.spawnItem(new ItemStack("minecraft:coal", currentCredits), this.getBlockCenter(block));
                    block.dimension.runCommand(`playsound random.pop @a ${location.x} ${location.y} ${location.z} 0.5`);

                    this.setBlockCredits(block, 0);

                }
            } catch (e) {
                //console.warn(e)
            }
        }, 1)
    }

    onTick(e) {
        const { block } = e;

        // Process the drop queue first
        if (this.dropQueue.length > 0) {
            this.processDropQueue(block);
            return; // Skip processing the chest while the queue is not empty
        }

        const direction = block.permutation.getState('minecraft:cardinal_direction');
        const oreResultIndex = block.permutation.getState('pb_red:ore_result');
        const chest = block.above();
        const { frontBlock, backBlock } = this.getFrontandBack(direction, block);

        if (!chest || !backBlock) return

        if (!this.isValidContainer(chest)) return;

        let inventory = chest.getComponent("minecraft:inventory")?.container;
        if (!inventory) return;

        const refinedOre = this.MINECRAFT_ORES_LOOT[oreResultIndex];
        const refinedOreCredit = this.ORE_CREDIT[oreResultIndex];

        let currentCredits = this.getBlockCredits(block);

        for (let slot = 0; slot < inventory.size; slot++) {
            const chestItem = inventory.getItem(slot);
            if (!chestItem || !this.isOreItem(chestItem.typeId)) continue;

            const inputOreIndex = this.MINECRAFT_ORES_LOOT.indexOf(chestItem.typeId);
            const inputOreCredit = this.ORE_CREDIT[inputOreIndex];

            currentCredits += chestItem.amount * inputOreCredit;

            inventory.setItem(slot, new ItemStack("minecraft:air", 1));
        }

        // Drop refined ore only when sufficient credits are available
        while (currentCredits >= refinedOreCredit) {
            const refinedAmount = Math.min(Math.floor(currentCredits / refinedOreCredit), 64);
            const dropAmount = Math.min(refinedAmount, 64);

            // Add the refined ore to the drop queue
            this.dropQueue.push({
                itemStack: new ItemStack(refinedOre, dropAmount),
                location: this.getBlockCenter(backBlock)
            });

            currentCredits -= dropAmount * refinedOreCredit;
        }

        // Update dynamic property for credits
        this.setBlockCredits(block, currentCredits);

        // Update the level state
        this.updateLevelState(block);
    }

    getFrontandBack(direction, block) {
        let frontBlock, backBlock;
        switch (direction) {
            case 'north':
                frontBlock = block.north();
                backBlock = block.south();
                break;
            case 'south':
                frontBlock = block.south();
                backBlock = block.north();
                break;
            case 'east':
                frontBlock = block.east();
                backBlock = block.west();
                break;
            case 'west':
                frontBlock = block.west();
                backBlock = block.east();
                break;
        }
        return { frontBlock, backBlock };
    }

    isValidContainer(block) {
        if (!block) return false;
        const validContainers = [
            "minecraft:chest",
            "minecraft:hopper",
            "minecraft:barrel",
            "minecraft:dropper",
            "minecraft:dispenser",
            "minecraft:trapped_chest",
            "minecraft:undyed_shulker_box",
            "minecraft:black_shulker_box",
            "minecraft:blue_shulker_box",
            "minecraft:brown_shulker_box",
            "minecraft:cyan_shulker_box",
            "minecraft:gray_shulker_box",
            "minecraft:green_shulker_box",
            "minecraft:light_blue_shulker_box",
            "minecraft:light_gray_shulker_box",
            "minecraft:lime_shulker_box",
            "minecraft:magenta_shulker_box",
            "minecraft:orange_shulker_box",
            "minecraft:pink_shulker_box",
            "minecraft:purple_shulker_box",
            "minecraft:red_shulker_box",
            "minecraft:white_shulker_box",
            "minecraft:yellow_shulker_box",
        ];
        return validContainers.includes(block.typeId);
    }

    isOreItem(id) {
        return this.MINECRAFT_ORES_LOOT.includes(id);
    }

    getBlockCenter(block) {
        const loc = block.location;
        return { x: loc.x + 0.5, y: loc.y + 0.5, z: loc.z + 0.5 };
    }
}
