import { world, system, BlockPermutation, ItemStack } from "@minecraft/server"
import { Vector } from './vector.js'


class PortableDropper {
    constructor() {

    }

    onItemUse(e) {
        const { itemStack, source } = e;
        if (source.typeId === "minecraft:player" && itemStack.typeId === "pb_red:spawn_portable_dropper") {
            const minecart = source.getEntitiesFromViewDirection()[0]?.entity;
            if (!minecart) return;
            const alreadydropper = source.dimension.getEntities({ type: "pb_red:portable_dropper", location: minecart.location, maxDistance: 1 })[0]
            if (alreadydropper) return;
            if (minecart.typeId === "minecraft:minecart" && this.isWithinDistance(minecart.location, source.location, 6)) {
                minecart.runCommand(`ride @s summon_rider pb_red:portable_dropper`);
                const dropperEntity = source.dimension.getEntities({ type: "pb_red:portable_dropper", location: minecart.location, maxDistance: 1 })[0]
                dropperEntity.nameTag = "§r"
                dropperEntity.setRotation(minecart.getRotation())
                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:portable_dropper_despawn') {
            this.handledropperDespawn(sourceEntity);
        } else if (id === 'pb_red:portable_dropper_working') {
            this.handledropper(sourceEntity);
        } else if (id === 'pb_red:portable_dropper_interact') {
            this.dropperBonusRotation(sourceEntity);
        }
    }

    dropperBonusRotation(sourceEntity) {
        let bonusRotation = sourceEntity.getDynamicProperty("pb_red:portable_dropper:bonus_rotation") || 0
        bonusRotation += 90
        if (bonusRotation >= 360) bonusRotation -= 360

        sourceEntity.dimension.runCommand(`playsound vr.stutterturn @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z}`);

        sourceEntity.setDynamicProperty("pb_red:portable_dropper:bonus_rotation", bonusRotation)
    }

    handledropperDespawn(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_portable_dropper", 1), location);
        sourceEntity.dimension.runCommand(`playsound random.break @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z}`);
        sourceEntity.remove();
    }

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

        try {
            let accessTest = sourceEntity.dimension;
        } catch {
            return;
        }

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

        if (!minecart) return;

        const bonusRotation = sourceEntity.getDynamicProperty("pb_red:portable_dropper:bonus_rotation") || 0

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

        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 offset = this.getOffsetsByViewDirection(viewDirection);
        if (!offset) return

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

    getOffsetsByViewDirection(viewDirection) {
        switch (viewDirection) {
            case 0:
            case 360:
                return { x: 1.5, z: 0 };
            case 90:
            case -270:
                return { x: 0, z: 1.5 };
            case 180:
            case -180:
                return { x: -1.5, z: 0 };
            case 270:
            case -90:
                return { x: 0, z: -1.5 };
            default:
                return null;
        }
    }

    dropIfPossible(sourceEntity, inv, blockPos) {
        const block = sourceEntity.dimension.getBlock(sourceEntity.location);
        if (!block) return

        let previousRail = sourceEntity.getDynamicProperty("pb_red:portable_dropper:previous_rail") || JSON.stringify({ x: 0, y: 0, z: 0 })
        previousRail = JSON.parse(previousRail)

        if (block.permutation.matches("minecraft:detector_rail") && (block.location.x !== previousRail.x || block.location.y !== previousRail.y || block.location.z !== previousRail.z)) {

            for (let i = 0; i < inv.size; i++) {
                const item = inv.getItem(i);

                if (item && item.amount > 0) {

                    const projectiles = [
                        "minecraft:arrow",
                        "minecraft:egg",
                        "minecraft:snowball"
                    ]

                    if (projectiles.includes(item.typeId)) {
                        if (item.amount === 1) {
                            inv.setItem(i, null);
                        } else {
                            item.amount--;
                            inv.setItem(i, item);
                        }
                        const spawnPos = Vector.add(blockPos, { x: 0, y: 0.5, z: 0 })
                        const arrow = sourceEntity.dimension.spawnEntity(item.typeId, spawnPos)

                        const impulseVec = Vector.subtract(blockPos, sourceEntity.location).multiply(2)
                        arrow.setRotation({ x: sourceEntity.getRotation().x, y: sourceEntity.getRotation().y + 90 })
                        arrow.applyImpulse(impulseVec)

                        sourceEntity.dimension.runCommand(`playsound random.click @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} 0.8`);

                    } else if (item.typeId == "minecraft:tnt") {
                        if (item.amount === 1) {
                            inv.setItem(i, null);
                        } else {
                            item.amount--;
                            inv.setItem(i, item);
                        }

                        const tnt = sourceEntity.dimension.spawnEntity("minecraft:tnt", blockPos)

                        sourceEntity.dimension.runCommand(`playsound random.click @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} 0.8`);

                    } else {
                        inv.setItem(i, null);
                        //  console.warn(block.x, blockPos.y, blockPos.z)

                        const spawnedItem = sourceEntity.dimension.spawnItem(item, blockPos)

                        sourceEntity.dimension.runCommand(`playsound random.click @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} 0.8`);
                        system.runTimeout(() => {
                            sourceEntity.dimension.runCommand(`playsound random.pop @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} 0.8`);
                        }, 5)
                    }

                    sourceEntity.setDynamicProperty("pb_red:portable_dropper:previous_rail", JSON.stringify({ x: block.location.x, y: block.location.y, z: block.location.z }))
                    break;
                }
            }

        }


    }

}




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

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