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


class Harvester {
    constructor() {
        this.validSeeds = [
            "minecraft:wheat_seeds", "minecraft:carrot", "minecraft:potato",
            "minecraft:beetroot_seeds", "minecraft:pumpkin_seeds", "minecraft:melon_seeds",
            "minecraft:torchflower_seeds", "minecraft:pitcher_pod", "minecraft:pumpkin",
            "minecraft:melon_slice", "minecraft:wheat", "minecraft:beetroot", "minecraft:torchflower", "minecraft:pitcher_plant"
        ];
        this.seedsBlock = [
            "minecraft:wheat", "minecraft:carrots", "minecraft:potatoes",
            "minecraft:beetroot", "minecraft:pumpkin", "minecraft:melon_block",
            "minecraft:torchflower_crop", "minecraft:pitcher_crop"
        ];
        this.tickCpt = 0;
    }

    onItemUse(e) {
        const { itemStack, source } = e;
        if (source.typeId === "minecraft:player" && itemStack.typeId === "pb_red:spawn_harvester") {
            const minecart = source.getEntitiesFromViewDirection()[0]?.entity;
            if (!minecart) return;
            const alreadyharvester = source.dimension.getEntities({ type: "pb_red:harvester", location: minecart.location, maxDistance: 1 })[0]
            if (alreadyharvester) return;
            if (minecart.typeId === "minecraft:minecart" && this.isWithinDistance(minecart.location, source.location, 6)) {
                minecart.runCommand(`ride @s summon_rider pb_red:harvester`);
                const harvesterEntity = source.dimension.getEntities({ type: "pb_red:harvester", location: minecart.location, maxDistance: 1 })[0]
                harvesterEntity.nameTag = "§r"
                minecart.dimension.runCommand(`playsound mob.agent.spawn @a ${minecart.location.x} ${minecart.location.y} ${minecart.location.z}`);
                source.runCommand(`clear @s ${itemStack.typeId} 0 1`);
            }
        }
    }

    isWithinDistance(pos1, pos2, maxDistance) {
        const distance = Math.sqrt(
            Math.pow(pos2.x - pos1.x, 2) +
            Math.pow(pos2.y - pos1.y, 2) +
            Math.pow(pos2.z - pos1.z, 2)
        );
        return distance <= maxDistance;
    }

    onScriptEventReceive(data) {
        const { id, sourceEntity } = data;

        if (id === 'pb_red:harvester_despawn') {
            this.handleharvesterDespawn(sourceEntity);
        } else if (id === 'pb_red:harvester_plant') {
            this.handleharvesterPlant(sourceEntity);
        }
    }

    handleharvesterDespawn(sourceEntity) {
        const inv = sourceEntity.getComponent('inventory').container;
        const location = { x: sourceEntity.location.x, y: sourceEntity.location.y + 1, z: sourceEntity.location.z };
        for (let i = 0; i < inv.size; i++) {
            const item = inv.getItem(i);
            if (item) sourceEntity.dimension.spawnItem(item, location);
        }
        sourceEntity.dimension.spawnItem(new ItemStack("pb_red:spawn_harvester", 1), location);
        sourceEntity.dimension.runCommand(`playsound random.break @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z}`);
        sourceEntity.remove();
    }

    handleharvesterPlant(sourceEntity) {
        if (!sourceEntity) return;

        try {
            let removeDimension = sourceEntity.dimension;
        } catch {
            // console.warn('harvester has been removed');
            return;
        }

        const minecart = sourceEntity.dimension.getEntities({
            location: sourceEntity.location,
            maxDistance: 1,
            type: 'minecraft:minecart'
        })[0];

        if (!minecart) return;

        sourceEntity.setRotation({
            x: minecart.getRotation().x,
            y: minecart.getRotation().y + 90
        });

        const inv = sourceEntity.getComponent('inventory').container;
        let globalSpeed = Math.sqrt(sourceEntity.getVelocity().x ** 2 + sourceEntity.getVelocity().z ** 2);

        if (globalSpeed < 0.01) return;

        const viewDirection = sourceEntity.getRotation().y;
        if (viewDirection % 90 !== 0) return;

        const offsets = this.getOffsetsByViewDirection(viewDirection);
        this.tickCpt++
        if (this.tickCpt % 50 == 0) {
            sourceEntity.dimension.runCommand(`playsound pb_red.harvester_loop @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} 0.8`);
        }

        offsets.forEach(offset => {
            const blockPos = {
                x: sourceEntity.location.x + offset.x,
                y: sourceEntity.location.y,
                z: sourceEntity.location.z + offset.z
            };
            this.harvestCropsIfPossible(sourceEntity, inv, blockPos);
        });
    }

    getOffsetsByViewDirection(viewDirection) {
        switch (viewDirection) {
            case 0:
            case 360:
                return [
                    { x: 1, z: 0 }, { x: 2, z: 0 }, { x: 3, z: 0 },
                    { x: -1, z: 0 }, { x: -2, z: 0 }, { x: -3, z: 0 }
                ];
            case 90:
            case -270:
                return [
                    { x: 0, z: 1 }, { x: 0, z: 2 }, { x: 0, z: 3 },
                    { x: 0, z: -1 }, { x: 0, z: -2 }, { x: 0, z: -3 }
                ];
            case 180:
            case -180:
                return [
                    { x: -1, z: 0 }, { x: -2, z: 0 }, { x: -3, z: 0 },
                    { x: 1, z: 0 }, { x: 2, z: 0 }, { x: 3, z: 0 }
                ];
            case 270:
            case -90:
                return [
                    { x: 0, z: -1 }, { x: 0, z: -2 }, { x: 0, z: -3 },
                    { x: 0, z: 1 }, { x: 0, z: 2 }, { x: 0, z: 3 }
                ];
            default:
                return [];
        }
    }

    harvestCropsIfPossible(sourceEntity, inv, blockPos) {
        const block = sourceEntity.dimension.getBlock(blockPos).below();
        const blockBelow = block.below();

        if (
            (this.seedsBlock.includes(block.typeId) && block.permutation.getState("growth") == 7 && blockBelow.permutation.matches("minecraft:farmland")) ||
            (block.permutation.matches("minecraft:pitcher_crop")
                || block.permutation.matches("minecraft:torchflower")
                || block.permutation.matches("minecraft:melon_block")
                || block.permutation.matches("minecraft:pumpkin"))
        ) {

            block.dimension.runCommand(`setblock ${block.location.x} ${block.location.y} ${block.location.z} air destroy`);

        }

        const itemsAround = block.dimension.getEntities({
            location: block.location,
            maxDistance: 2,
            type: "item"
        });

        itemsAround.forEach(itemEntity => {
            const itemStack = itemEntity.getComponent("minecraft:item").itemStack;
            if (!this.validSeeds.includes(itemStack.typeId)) return

            let addedToInventory = false;
            for (let i = 0; i < inv.size; i++) {
                const invItem = inv.getItem(i);
                if (!invItem) {
                    inv.setItem(i, itemStack);
                    addedToInventory = true;
                    break;
                } else if (invItem.typeId === itemStack.typeId && itemStack.amount <= (invItem.maxAmount - invItem.amount)) {
                    invItem.amount += itemStack.amount;
                    inv.setItem(i, invItem);
                    addedToInventory = true;
                    break;
                }
            }

            if (addedToInventory) {
                itemEntity.remove();
            }
        });
    }

}




const harvester = new Harvester();
world.afterEvents.itemUse.subscribe((e) => {
    harvester.onItemUse(e)
})

system.afterEvents.scriptEventReceive.subscribe((data) => {
    harvester.onScriptEventReceive(data)
})
