const SHIELD_LEASH = 80

var BlockPos = Java.loadClass('net.minecraft.core.BlockPos');

let $ResourceKey = Java.loadClass("net.minecraft.resources.ResourceKey")
let DAMAGE_TYPE = $ResourceKey.createRegistryKey("damage_type")

function getDamageSourceBothSides(
    /** @type {Internal.Level}*/ level,
    /** @type {Internal.DamageType_}*/ damageType,
    /** @type {Internal.LivingEntity}*/ destEntity,
    /** @type {Internal.LivingEntity}*/ sourceEntity
    ) {
    var resourceKey = $ResourceKey.create(DAMAGE_TYPE, Utils.id(damageType))
    var holder = level.registryAccess().registryOrThrow(DAMAGE_TYPE).getHolderOrThrow(resourceKey)
    var damagesourceholder = holder
    return new DamageSource(damagesourceholder, sourceEntity, destEntity)
}

ItemEvents.rightClicked('arrzenhanced:speedburst_shield', (event) => {
    let player = event.player
    
    // player.tell("stormin my breaker")
    
    if (player.isCrouching() && player.getMainHandItem().id == "arrzenhanced:speedburst_shield") {
        // player.tell("THROW")
        let lookAngle = player.getLookAngle().scale(SHIELD_LEASH)
        let playerLocation = Vec3d(
            player.getX(),
            player.getY(),
            player.getZ()
        )
        let targetLocation = Vec3d(
            (playerLocation.x() + lookAngle.x()),
            (playerLocation.y() + lookAngle.y()),
            (playerLocation.z() + lookAngle.z())
        )

        // player.tell(`coords: ${targetLocation.x()}, ${targetLocation.y()}, ${targetLocation.z()}`)

        let shieldHolder = player.getLevel().createEntity("minecraft:armor_stand");
        shieldHolder.setItemSlot(
            5, // helmet
            Item.of(
                event.player.getMainHandItem().id,
                event.player.getMainHandItem().count,
                event.player.getMainHandItem().nbt
            )
        );
        let tagname = "SpeedburstShield" + player.name.getString()
        shieldHolder.setNbt({Invisible:true, Marker:true});
        shieldHolder.tags.add(tagname)

        let otherLookAngle = player.getLookAngle().scale(1) // 1 blocks in front of them
        let spawnStandLoc = Vec3d(
            (playerLocation.x() + otherLookAngle.x()),
            (playerLocation.y() + otherLookAngle.y()),
            (playerLocation.z() + otherLookAngle.z())
        )

        shieldHolder.setPosition(spawnStandLoc.x(), spawnStandLoc.y()-0.5, spawnStandLoc.z());
        shieldHolder.spawn();
        event.player.mainHandItem.count = 0
        
        flyingShields[shieldHolder.id] = targetLocation
    }
})

var flyingShields = {}
var reachedTargetShields = {}
var soundtracker = {}

PlayerEvents.tick((event) => {
    let player = event.player
    let tagname = 'SpeedburstShield' + player.name.getString()
    player.getLevel().getEntities().forEach((entity) => {
        if (entity.type != 'minecraft:armor_stand') return
        if (!entity.tags.contains(tagname)) return
        entity.setRotation(entity.getRotationVector().y + 40, 0)
        // player.tell(entity.id)
        if (flyingShields[entity.id] == undefined) {
            // player.tell("nowhere to go!")

            var inven = entity.getAllSlots()
            inven.forEach((item) => {
                if (item.isEmpty()) return
                /*
                let ourItem = player.getLevel().createEntity('minecraft:item')
                ourItem.item = Item.of(item.id, item.count, item.nbt)
                ourItem.setPosition(
                    player.getX(),
                    player.getY(),
                    player.getZ()
                )
                ourItem.spawn()
                */
                event.server.runCommandSilent(`stopsound @a * arrzenhanced:shieldthrowloop`)
                player.give(Item.of(item.id, item.count, item.nbt))
                delete soundtracker[entity.id]
                delete reachedTargetShields[entity.id]
                delete flyingShields[entity.id]
            })

            entity.kill()
        } else {
            if (!soundtracker[entity.id]) {
                soundtracker[entity.id] = 1
                var px = entity.getX();
                var py = entity.getY();
                var pz = entity.getZ();
                // let blockPos = new BlockPos(px, py, pz)
                event.server.runCommandSilent(`playsound arrzenhanced:shieldthrowloop master @a ${px} ${py} ${pz} 1 1`)
                // entity.getLevel().playSound(player, blockPos.pos, "arrzenhanced:shieldthrowloop", "master", 0.5, 1)
            } else {soundtracker[entity.id] += 1}
            let targetPos = flyingShields[entity.id]
            let dirToTarget = {
                x: targetPos.x() - entity.getX(),
                y: targetPos.y() - entity.getY(),
                z: targetPos.z() - entity.getZ()
            };
            let distance = Math.sqrt(
                dirToTarget.x * dirToTarget.x +
                dirToTarget.y * dirToTarget.y +
                dirToTarget.z * dirToTarget.z
            );

            // Check if the entity has reached its target (within 0.25 blocks)
            // player.tell(distance)
            if (reachedTargetShields[entity.id]) {
                flyingShields[entity.id] = Vec3d(
                    player.getX(),
                    player.getY(),
                    player.getZ()
                )
            }

            if (distance <= 0.8) {
                // Update the target to the player's current position
                if (reachedTargetShields[entity.id] == undefined) {
                    reachedTargetShields[entity.id] = true
                } else {
                    // drop the weapon
                    var inven = entity.getAllSlots()
                    inven.forEach((item) => {
                        if (item.isEmpty()) return
                        /*
                        let ourItem = entity.getLevel().createEntity('minecraft:item')
                        ourItem.item = Item.of(item.id, item.count, item.nbt)
                        ourItem.setPosition(
                            entity.getX(),
                            entity.getY(),
                            entity.getZ()
                        )
                        ourItem.spawn()
                        */
                        player.give(Item.of(item.id, item.count, item.nbt))
                    })
                    event.server.runCommandSilent(`stopsound @a * arrzenhanced:shieldthrowloop`)
                    entity.kill()
                    delete soundtracker[entity.id]
                    delete reachedTargetShields[entity.id]
                    delete flyingShields[entity.id]
                }
                
                flyingShields[entity.id] = Vec3d(
                    player.getX(),
                    player.getY(),
                    player.getZ()
                )
                let targetPos = flyingShields[entity.id]

                dirToTarget = {
                    x: targetPos.x() - entity.getX(),
                    y: targetPos.y() - entity.getY(),
                    z: targetPos.z() - entity.getZ()
                };
                distance = Math.sqrt(
                    dirToTarget.x * dirToTarget.x +
                    dirToTarget.y * dirToTarget.y +
                    dirToTarget.z * dirToTarget.z
                );
            }

            // Check if the entity collides with a block
            let block = player.getLevel().getBlock(
                Math.floor(entity.getX()),
                Math.floor(entity.getY()+1),
                Math.floor(entity.getZ())
            )
            if (
                !(
                    block == 'minecraft:air' ||
                    block == 'minecraft:water' ||
                    block == 'minecraft:tall_grass' ||
                    block == 'minecraft:grass' ||
                    block == 'minecraft:lava' ||
                    block == 'minecraft:light'
                )
            ) {
                // Update the target to the player's current position
                if (reachedTargetShields[entity.id] == undefined) {
                    reachedTargetShields[entity.id] = true
                }
            }


            if (distance > 0.01) {
                // Normalize the direction vector
                dirToTarget.x /= distance;
                dirToTarget.y /= distance;
                dirToTarget.z /= distance;

                // Move the entity by 0.25 blocks in the direction of the target
                // let speed = 0.8;
                let speed = 1.6;
                entity.teleportTo(
                    entity.x + dirToTarget.x * speed,
                    entity.y + dirToTarget.y * speed,
                    entity.z + dirToTarget.z * speed
                );
            }

            // deal damage to nearby entities
            entity.getLevel().getEntitiesWithin(AABB.of(
                entity.getX()+1,
                entity.getY()+2,
                entity.getZ()+1,
                entity.getX()-1,
                entity.getY()+1,
                entity.getZ()-1,
            )).forEach((target) => {
                if (target == event.player) return;
                if (target.type == 'minecraft:item') return;
                let damageSource = getDamageSourceBothSides(event.player.getLevel(), "minecraft:player_attack", target, event.player)
                target.attack(damageSource, 7)
                if (reachedTargetShields[entity.id] == undefined) {
                    reachedTargetShields[entity.id] = true
                }
            })
            //120 v1
            //24 v2
            //16 v3
            if (soundtracker[entity.id] % 120 == 0) {
                event.server.runCommandSilent(`stopsound @a * arrzenhanced:shieldthrowloop`)
                var px = entity.getX();
                var py = entity.getY();
                var pz = entity.getZ();
                // let blockPos = new BlockPos(px, py, pz)
                // entity.getLevel().playSound(player, px, py, pz, "arrzenhanced:shieldthrowloop", "master", 0.5, 1)
                event.server.runCommandSilent(`playsound arrzenhanced:shieldthrowloop master @a ${px} ${py} ${pz} 1 1`)
            }
        }
    })
})