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


class PortableBlockDispenser {
    constructor() {

    }

    onItemUse(e) {
        const { itemStack, source } = e;
        if (source.typeId === "minecraft:player" && itemStack.typeId === "pb_red:spawn_portable_block_dispenser") {
            const minecart = source.getEntitiesFromViewDirection()[0]?.entity;
            if (!minecart) return;
            const alreadydispenser = source.dimension.getEntities({ type: "pb_red:portable_block_dispenser", location: minecart.location, maxDistance: 1 })[0]
            if (alreadydispenser) return;
            if (minecart.typeId === "minecraft:minecart" && this.isWithinDistance(minecart.location, source.location, 6)) {
                minecart.runCommand(`ride @s summon_rider pb_red:portable_block_dispenser`);
                const dispenserEntity = source.dimension.getEntities({ type: "pb_red:portable_block_dispenser", location: minecart.location, maxDistance: 1 })[0]
                dispenserEntity.nameTag = "§r"
                dispenserEntity.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`);
            }

            // HANDLE PLACEMENT ON RAIL PLACER

        }
    }

    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_block_dispenser_despawn') {
            this.handledispenserDespawn(sourceEntity);
        } else if (id === 'pb_red:portable_block_dispenser_working') {
            this.handledispenser(sourceEntity);
        } else if (id === 'pb_red:portable_block_dispenser_interact') {
            this.dispenserBonusRotation(sourceEntity);
        }
    }

    dispenserBonusRotation(sourceEntity) {
        let onRailPlacer = sourceEntity.getProperty("pb_red:is_on_rail_placer")
        if (onRailPlacer) return

        let bonusRotation = sourceEntity.getProperty("pb_red:rotation_config") || "up"
        if (bonusRotation == "left") {
            bonusRotation = 90
            sourceEntity.setProperty("pb_red:rotation_config", "right")
        }
        if (bonusRotation == "right") {
            bonusRotation = 0
            sourceEntity.setProperty("pb_red:rotation_config", "up")
        }
        if (bonusRotation == "up") {
            bonusRotation = -90
            sourceEntity.setProperty("pb_red:rotation_config", "left")
        }

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

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

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

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

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

        let onRailPlacer = sourceEntity.getProperty("pb_red:is_on_rail_placer")

        let blockPos = {
            x: sourceEntity.location.x,
            y: sourceEntity.location.y,
            z: sourceEntity.location.z
        };
        let backBlockPos = null
        const inv = sourceEntity.getComponent('inventory').container;

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

            if (!minecart) return;


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

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

            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

            blockPos = {
                x: sourceEntity.location.x + offset.x,
                y: sourceEntity.location.y,
                z: sourceEntity.location.z + offset.z
            };

            if (bonusRotation == 0) {
                blockPos = {
                    x: sourceEntity.location.x,
                    y: sourceEntity.location.y + 2.1,
                    z: sourceEntity.location.z
                };

            }
        } else {
            blockPos = {
                x: sourceEntity.location.x,
                y: sourceEntity.location.y - 1,
                z: sourceEntity.location.z
            };
            let viewDirection = sourceEntity.getRotation().y + 270;
            if (viewDirection >= 360) viewDirection -= 360
            if (viewDirection % 90 !== 0) return;

            const offset = this.getOffsetsByViewDirection(viewDirection);

            backBlockPos = {
                x: sourceEntity.location.x + offset.x,
                y: sourceEntity.location.y,
                z: sourceEntity.location.z + offset.z
            };

        }

        this.placeIfPossible(sourceEntity, inv, blockPos, onRailPlacer, backBlockPos);
    }

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

    isRail(block) {
        return block.typeId.includes("rail") && block.typeId.startsWith("minecraft:")
    }

    placeIfPossible(sourceEntity, inv, blockPos, onRailPlacer, backBlockPos) {

        const block = sourceEntity.dimension.getBlock(sourceEntity.location);
        const blockToPlace = sourceEntity.dimension.getBlock(blockPos);
        const backBlock = sourceEntity.dimension.getBlock(backBlockPos ? backBlockPos : blockPos);

        if (!block || !blockToPlace || !backBlock) return

        if (block.typeId == "minecraft:detector_rail" || (onRailPlacer == true && this.isRail(backBlock))) {

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

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

                    if (blockToPlace.typeId == "minecraft:air" || blockToPlace.typeId.includes("lava") || blockToPlace.typeId.includes("water")) {
                        let placeSuccess = false
                        try {
                            blockToPlace.setType(item.typeId);
                            placeSuccess = true
                        } catch {
                            placeSuccess = false
                            // console.warn("error")
                        }

                        if (placeSuccess) {
                            if (item.amount === 1) {
                                inv.setItem(i, null);
                            } else {
                                item.amount--;
                                inv.setItem(i, item);
                            }

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


                        break;
                    }

                }
            }

        }


    }

}




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

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