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


class PortableMagnet {
    constructor() {
        this.tickCpt = 0

        this.ENCHANTMENT_TYPES = [
            { type: "efficiency", level: 1 },
            { type: "efficiency", level: 2 },
            { type: "efficiency", level: 3 },
            { type: "efficiency", level: 4 },
            { type: "efficiency", level: 5 }
        ];
    }

    onItemUse(e) {
        const { itemStack, source } = e;
        if (source.typeId === "minecraft:player" && itemStack.typeId === "pb_red:spawn_portable_magnet") {
            const minecart = source.getEntitiesFromViewDirection()[0]?.entity;
            if (!minecart) return;
            const alreadymagnet = source.dimension.getEntities({ type: "pb_red:portable_magnet", location: minecart.location, maxDistance: 1 })[0]
            if (alreadymagnet) return;
            if (minecart.typeId === "minecraft:minecart" && this.isWithinDistance(minecart.location, source.location, 6)) {
                minecart.runCommand(`ride @s summon_rider pb_red:portable_magnet`);
                const magnetEntity = source.dimension.getEntities({ type: "pb_red:portable_magnet", location: minecart.location, maxDistance: 1 })[0]
                magnetEntity.nameTag = "§r"
                magnetEntity.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_magnet_despawn') {
            this.handlemagnetDespawn(sourceEntity);
        } else if (id === 'pb_red:portable_magnet_working') {
            this.handlemagnet(sourceEntity);
        } else if (id === 'pb_red:portable_magnet_interact') {
            const player = sourceEntity.dimension.getEntities({ type: "minecraft:player", location: sourceEntity.location, maxDistance: 10 })[0]
            if (!player) return
            let selectedSlot = player.selectedSlotIndex;
            let handItem = player.getComponent("inventory").container.getItem(selectedSlot);
            if (!handItem) return

            if (handItem.typeId == "pb_red:redstone_wrench") {
                const efficiency = sourceEntity.getProperty('pb_red:efficiency')

                sourceEntity.dimension.runCommand(`playsound random.click @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z}`)
                player.sendMessage(`Portable Magnet range: ${10 + (efficiency * 2)}`)
                return;

            } else if (handItem.typeId.includes('enchanted_book')) {
                const enchantment = handItem.getComponent("enchantable");

                for (let i = 0; i < this.ENCHANTMENT_TYPES.length; i++) {
                    let enchantmentType = this.ENCHANTMENT_TYPES[i];
                    if (enchantment.hasEnchantment(new EnchantmentType(enchantmentType.type))) {
                        let enchantLevel = enchantment.getEnchantment(new EnchantmentType(enchantmentType.type)).level;
                        sourceEntity.setProperty(`pb_red:${enchantmentType.type}`, enchantLevel);
                        player.getComponent("inventory").container.setItem(selectedSlot, null);
                        player.runCommand(`tellraw @s {"rawtext":[{"text":"Upgraded Portable Magnet with §d${enchantmentType.type} ${enchantLevel}."}]}`)
                        sourceEntity.dimension.runCommand(`playsound random.orb @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z}`)
                        return;
                    }
                }
            }
        }
    }

    handlemagnetDespawn(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);
        }

        const efficiency = sourceEntity.getProperty('pb_red:efficiency')
        if (efficiency > 0)
            sourceEntity.dimension.runCommand(`loot spawn ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} loot "pb/redstone/upgrade/efficiency_${efficiency}"`)

        sourceEntity.dimension.spawnItem(new ItemStack("pb_red:spawn_portable_magnet", 1), location);
        sourceEntity.dimension.runCommand(`playsound random.break @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z}`);
        sourceEntity.remove();
    }

    handlemagnet(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;

        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;

        this.magnetIfPossible(sourceEntity, inv);
    }

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

        const efficiency = sourceEntity.getProperty('pb_red:efficiency')

        const entities = sourceEntity.dimension.getEntities({
            location: sourceEntity.location,
            maxDistance: 10 + (efficiency * 2),
            type: 'minecraft:item'
        });
        if (entities.length > 0) {
            block.dimension.spawnParticle("pb_red:magnet_active", Vector.add(sourceEntity.location, { x: 0, y: 1.5, z: 0 }));
            this.tickCpt++
            if (this.tickCpt % 21 == 0) {
                block.dimension.runCommand(`playsound pb_red.magnet_loop @a ${sourceEntity.location.x} ${sourceEntity.location.y} ${sourceEntity.location.z} 1.2`)
            }
        }

        for (const entity of entities) {

            const dx = sourceEntity.location.x - entity.location.x;
            const dy = sourceEntity.location.y - entity.location.y;
            const dz = sourceEntity.location.z - entity.location.z;

            const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
            if (distance > 2) {
                let force = 0
                if (distance > 2)
                    force = 1 / distance;
                else
                    force = distance * 0.1;

                let impulseVector = { x: 0, y: 0, z: 0 };
                impulseVector.x = (dx / distance) * force;
                impulseVector.y = (dy / distance) * force;
                impulseVector.z = (dz / distance) * force;

                entity.applyImpulse(impulseVector);

            } else {
                const itemStack = entity.getComponent("minecraft:item").itemStack;

                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) {
                    entity.remove();
                }


            }

        }


    }

}




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

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