import { world, system, Player, GameMode } from "@minecraft/server"

const messageTag = "lb_as:fly_message"

export const bossArmorItems = {
    callback: (player) => bossArmor(player),
    items: [
        "lb_as:boss_helmet",
        "lb_as:boss_chestplate",
        "lb_as:boss_leggings",
        "lb_as:boss_boots"
    ]
}

const maxFlyTime = 10

const cooldownProperty = "lb_as:fly_cooldown"
const speedProperty = "lb_as:speed_effect"
const verticalStrength = 0.6
let slowFall = {} // true = yes slow fall

/**
 * @param {Player} player 
 */
function bossArmor(player) {
    if (!player.hasTag(messageTag)) {
        player.sendMessage({translate: "text.armor.first_equip"})
        player.addTag(messageTag)
    }
    if (player.getGameMode() === GameMode.Creative) return
    if (slowFall[player.id] && !player.isOnGround) player.addEffect('slow_falling', 1, { showParticles: false })
    if (player.getDynamicProperty(speedProperty)) player.addEffect("speed", 5, { showParticles: false })
    player.addEffect('fire_resistance', 1, { showParticles: false })

    const hasJumpTag1 = player.getTags().find(tag => tag.startsWith('lb_as:jump_tag_1'))
    const hasJumpTag2 = player.getTags().find(tag => tag.startsWith('lb_as:jump_tag_2'))

    if (player.isJumping && !hasJumpTag1) {
        player.addTag('lb_as:jump_tag_1')

        let interval
        let timeout

        interval = system.runInterval(() => {
            if (!player.isJumping) {
                system.clearRun(interval)
                system.clearRun(timeout)
                interval = system.runInterval(() => {
                    if (player.isJumping) {
                        system.run(() => player.removeTag('lb_as:jump_tag_1'))
                        system.clearRun(interval)
                        system.clearRun(timeout)

                        if (!player.hasTag('lb_as:jump_tag_2')) {
                            slowFall[player.id] = true
                            player.setDynamicProperty(speedProperty, true)
                            player.addTag('lb_as:jump_tag_2')
                        } else {
                            player.onScreenDisplay.setActionBar(`:hollow_star: ${getDurationBar()}`)
                            player.setDynamicProperty(speedProperty, false)
                            player.removeTag('lb_as:jump_tag_2')
                        }
                    }
                })

                timeout = system.runTimeout(() => {
                    system.clearRun(interval)
                    player.removeTag('lb_as:jump_tag_1')
                }, 5)
            }
        })


        timeout = system.runTimeout(() => {
            system.clearRun(interval)
            player.removeTag('lb_as:jump_tag_1')
        }, 5)
    }

    if (!player.getDynamicPropertyIds().includes(cooldownProperty)) player.setDynamicProperty(cooldownProperty, 0)

    if (hasJumpTag2) {
        player.onScreenDisplay.setActionBar(`:solid_star: ${getDurationBar()}`)
        const number = player.getDynamicProperty(cooldownProperty)

        if (player.isOnGround) reduceCooldown()
        else {
            if (number / 20 >= maxFlyTime) {
                airMovementWithoutEnergy()
                return
            }
            addCooldown()
            airMovement()
        }

        function addCooldown() {
            player.setDynamicProperty(cooldownProperty, number + 1)
        }

        function airMovement() {
            const playerRotation = player.getRotation().y
            const inputDirection = player.inputInfo.getMovementVector()
            const yInputDirection = player.isJumping ? verticalStrength : player.isSneaking ? -verticalStrength * 0.75 : 0

            const knockbackDirection = inputToWorldDirection(inputDirection, playerRotation)

            if (knockbackDirection.x != 0 || knockbackDirection.z != 0 || yInputDirection != 0) player.applyKnockback(knockbackDirection, yInputDirection)

            function inputToWorldDirection(input, yawDeg) {
                // Converte graus -> radianos
                const yaw = (yawDeg * Math.PI) / 180;

                // Forward no plano XZ
                const forward = {
                    x: Math.cos(yaw),
                    z: Math.sin(yaw)
                };

                // Right é 90° rotacionado
                const right = {
                    x: -Math.sin(yaw),
                    z: Math.cos(yaw)
                };

                // Combina input (x = frente/trás, y = esquerda/direita)
                let world = {
                    x: input.x * forward.x + input.y * right.x,
                    z: input.x * forward.z + input.y * right.z
                };

                // Normaliza pra não correr mais rápido na diagonal
                const len = Math.hypot(world.x, world.z);
                if (len > 0) {
                    world.x /= len;
                    world.z /= len;
                }

                return world; // vetor 2D XZ
            }
        }

        function airMovementWithoutEnergy() {
            const yInputDirection = player.isSneaking ? -1 : 0

            if (yInputDirection != 0) player.applyKnockback({ x: 0, z: 0 }, yInputDirection * verticalStrength)
        }
    } else if (player.isOnGround) {
        // slow fall until touch ground
        if (slowFall[player.id]) slowFall[player.id] = false
        reduceCooldown()
    }

    function reduceCooldown() {
        player.setDynamicProperty(cooldownProperty, 0)
    }

    function getDurationBar() {
        const number = player.getDynamicProperty(cooldownProperty)
        const charge = parseInt(10 - (number / 20))
        const uncharged = 10 - charge

        return `${"§f█".repeat(charge)}${"§8▒".repeat(uncharged)}`
    }
}