/*
    @author Hertz
    @version 1.0
*/

function resolveAllegedBooleanFromObject(thing) {
    if (thing.toString() == 'true') { return true; }
    if (thing.toString() == 'false') { return false; }
    return null
}

var $SuperpowerUtil = Java.loadClass('net.threetag.palladium.power.SuperpowerUtil')
var PlayerUtil = Java.loadClass('net.threetag.palladium.util.PlayerUtil');
var $UUID = Java.loadClass('java.util.UUID');

global.playSoundToAll = function(entity, range, sound, category, volume, pitch) {
    PlayerUtil['playSoundToAll(net.minecraft.world.level.Level,double,double,double,double,net.minecraft.resources.ResourceLocation,net.minecraft.sounds.SoundSource,float,float)'](entity.getLevel(), entity.x, entity.y, entity.z, range, sound, category, volume, pitch);
}

StartupEvents.registry('palladium:abilities', (event) => {
    
    event.create('arrzenhanced:configure_breach')
    .icon(palladium.createItemIcon('minecraft:end_portal_frame'))
    .tick((entity, entry, holder, enabled) => global.doBreachGUI(entity, entry, holder, enabled));

    event.create('arrzenhanced:summon_breach')
    .icon(palladium.createItemIcon('minecraft:end_portal_frame'))
    .addProperty("color", "integer", -1, "Hardcoded color")
    .firstTick((entity, entry, holder, enabled) => global.createBreachFirstTick(entity, entry, holder, enabled))
    .tick((entity, entry, holder, enabled) => global.createBreach(entity, entry, holder, enabled))
    .lastTick((entity, entry, holder, enabled) => global.createBreachLastTick(entity, entry, holder, enabled));

    event.create('arrzenhanced:breach_logic')
    .icon(palladium.createItemIcon('minecraft:end_portal_frame'))
    .tick((entity, entry, holder, enabled) => global.breachLogic(entity, entry, holder, enabled))

});

global.breachLogic = (entity, entry, holder, enabled) => {
    if (enabled) {
        var timer = palladium.getProperty(entity, 'arrzenhanced.warpwave.lifetime')
        var idle = palladium.getProperty(entity, 'arrzenhanced.warpwave.idle_frame')
        var open = palladium.getProperty(entity, 'arrzenhanced.warpwave.open_frame')

        if (idle >= 9) {palladium.setProperty(entity, 'arrzenhanced.warpwave.idle_frame', 0)} else {palladium.setProperty(entity, 'arrzenhanced.warpwave.idle_frame', idle+1)}
        if (open >= 14) {palladium.setProperty(entity, 'arrzenhanced.warpwave.open_frame', 0)} else {palladium.setProperty(entity, 'arrzenhanced.warpwave.open_frame', open+1)}
        palladium.setProperty(entity, 'arrzenhanced.warpwave.lifetime', timer+1)
        if (timer == 136) {
            palladium.setProperty(entity, 'arrzenhanced.warpwave.open_frame', 14)
        } else if (timer > 136 && timer < 150) {
            palladium.setProperty(entity, 'arrzenhanced.warpwave.open_frame', open-1)
        }

        let in_breach_aabb = entity.getLevel().getEntitiesWithin(AABB.of(
            entity.getX() + 1,
            entity.getY() + 1,
            entity.getZ() + 1,
            entity.getX() - 1,
            entity.getY(),
            entity.getZ() - 1,
        ))

        entity.getLevel().getEntitiesWithin(
            AABB.of(
                entity.getX() + 2,
                entity.getY() + 2,
                entity.getZ() + 2,
                entity.getX() - 2,
                entity.getY() - 2,
                entity.getZ() - 2,
            )
        ).forEach(target => {
            if (target.type != "minecraft:player") {return}
            if (in_breach_aabb.contains(target)) {return}
            target.tags.remove("arrz.in_breach")
        })

        in_breach_aabb.forEach(target => {
            if (target == entity) {return}
            // if (target.isLiving() == false) {return}
            // if (target.type != "minecraft:player") {return}
            if (target.tags.contains("arrz.in_breach")) {return}
            target.tags.add("arrz.in_breach")
            target.teleportTo(entity.persistentData.to_dim, entity.persistentData.to_x, entity.persistentData.to_y, entity.persistentData.to_z, target.getYaw(), target.getPitch())
            global.playSoundToAll(entity, 20, "arrzenhanced:warpwave_manipulation.exit_breach", "players", 1, 1)
            
            let tarUuid = $UUID.fromString(entity.persistentData.partnerUuid)
            let otherGuy = target.getServer().getLevel(entity.persistentData.to_dim).getEntity(tarUuid)

            if (otherGuy) {
                global.playSoundToAll(otherGuy, 20, "arrzenhanced:warpwave_manipulation.exit_breach", "players", 1, 1)
            }
        })

        if (timer >= 150) {
            Utils.server.runCommandSilent(`execute as ${entity.uuid.toString()} at ${entity.uuid.toString()} run forceload remove ~ ~`)
            // Utils.server.runCommandSilent(`kill ${entity.persistentData.partnerUuid}`)
            entity.kill()
        }
    }
}

global.createBreach = (entity, entry, holder, enabled) => {
    return
}

global.createBreachLastTick = (entity, entry, holder, enabled) => {
    return
}

global.createBreachFirstTick = (entity, entry, holder, enabled) => {
    if (enabled) {
        let lookAngle = entity.getLookAngle().scale(2);

        let playerLocation = Vec3d(entity.getX(), entity.getY(), entity.getZ());
        let targetLocation = Vec3d(
            playerLocation.x() + lookAngle.x(),
            playerLocation.y() + lookAngle.y(),
            playerLocation.z() + lookAngle.z()
        );
        let hard_color = entry.getPropertyByName("color")
        var color = 0
        if (hard_color == -1) {
            color = palladium.getProperty(entity, 'arrzenhanced.warpwave.color')
        } else {
            color = hard_color
        }

        let breach = entity.getLevel().createEntity('minecraft:armor_stand')
        let dest = entity.getServer().getLevel(entity.persistentData.warpwave.dim).createEntity('minecraft:armor_stand')

        breach.changeDimension(entity.getLevel())
        breach.setPosition(targetLocation.x(), targetLocation.y()+0.25, targetLocation.z())
        breach.mergeNbt({Invisible:true, Marker:true})
        breach.persistentData.to_x = entity.persistentData.warpwave.x
        breach.persistentData.to_y = entity.persistentData.warpwave.y
        breach.persistentData.to_z = entity.persistentData.warpwave.z
        breach.persistentData.to_dim = entity.persistentData.warpwave.dim
        breach.persistentData.partnerUuid = dest.uuid.toString()
        $SuperpowerUtil.addSuperpower(breach, "arrzenhanced:breach")
        palladium.setProperty(breach, 'arrzenhanced.warpwave.color', color)

        breach.setRotation(entity.getYaw(), -entity.getPitch())

        breach.spawn()
        Utils.server.runCommandSilent(`execute as ${breach.uuid.toString()} at ${breach.uuid.toString()} run forceload add ~ ~`)

        // other breach
        dest.setPosition(entity.persistentData.warpwave.x, entity.persistentData.warpwave.y, entity.persistentData.warpwave.z)
        dest.mergeNbt({Invisible:true, Marker:true})
        dest.persistentData.to_x = Math.round(targetLocation.x())
        dest.persistentData.to_y = Math.round(targetLocation.y())
        dest.persistentData.to_z = Math.round(targetLocation.z())
        dest.persistentData.to_dim = entity.getLevel().getDimension().toString()
        dest.persistentData.partnerUuid = breach.uuid.toString()
        $SuperpowerUtil.addSuperpower(dest, "arrzenhanced:breach")
        palladium.setProperty(dest, 'arrzenhanced.warpwave.color', color)

        dest.setRotation(entity.getYaw(), -entity.getPitch())

        dest.spawn()
        Utils.server.runCommandSilent(`execute as ${dest.uuid.toString()} at ${dest.uuid.toString()} in ${entity.getLevel().getDimension().toString()} run forceload add ~ ~`)
    }
}

global.doBreachGUI = (entity, entry, holder, enabled) => {
    if (enabled) {
        // delete entity.persistentData.warpwave
        if (!entity.persistentData.warpwave) {
            entity.persistentData.warpwave = {x: 0, y: 0, z: 0, dim:"minecraft:overworld"}
            entity.persistentData.warpwave.active = 1
            entity.persistentData.warpwave.way1 = {x: 0, y: 0, z: 0, dim:"minecraft:overworld"}
            entity.persistentData.warpwave.way2 = {x: 0, y: 0, z: 0, dim:"minecraft:overworld"}
            entity.persistentData.warpwave.way3 = {x: 0, y: 0, z: 0, dim:"minecraft:overworld"}
            entity.persistentData.warpwave.way4 = {x: 0, y: 0, z: 0, dim:"minecraft:overworld"}
            entity.persistentData.warpwave.way5 = {x: 0, y: 0, z: 0, dim:"minecraft:overworld"}
        }
        createui(entity)
    }
}

function createItemNBT(displayName, loreLines) {
    function formatText(text, color, bold, italic) {
        return {
            text: text,
            color: color,
            bold: bold,
            italic: italic
        };
    }

    var formattedLore = loreLines.map(line =>
        formatText(line.text, line.color, line.bold, line.italic)
    );

    var nbt = {
        display: {
            Name: JSON.stringify(formatText(displayName.text, displayName.color, displayName.bold, displayName.italic)),
            Lore: formattedLore.map(lore => JSON.stringify(lore))
        }
    };

    return nbt;
}


let createui = (player) => {
    // Slots go (X, Y) && Zero-indexed
    player.openChestGUI(Text.of(Text.aqua('Breach').bold()), 6, gui => {
        gui.playerSlots = false

        // Map Overhead
        gui.slot(4, 1, slot => {
            slot.item = Item.of(
                'minecraft:map',
                1,
                createItemNBT(
                    { text: "Active Coordinates", color: "white", bold: false, italic: false },
                    [
                        { text: ``, color: "white", bold: false, italic: false },
                        { text: `X: ${player.persistentData.warpwave.x}`, color: "white", bold: false, italic: false },
                        { text: `Y: ${player.persistentData.warpwave.y}`, color: "white", bold: false, italic: false },
                        { text: `Z: ${player.persistentData.warpwave.z}`, color: "white", bold: false, italic: false },
                        { text: `Dimension: ${player.persistentData.warpwave.dim}`, color: "white", bold: false, italic: false }
                    ]
                )
            )
            slot.leftClicked = (e) => {
                // player.sendSystemMessage('§ayummers')
                createui(player)
            }
        })
        // Get Current Coords Button
        gui.slot(7, 0, slot => {
            slot.item = Item.of(
                'minecraft:dirt_path',
                1,
                createItemNBT(
                    { text: "Import Current Coordinates", color: "green", bold: true, italic: false },
                    []
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x = Math.floor(player.getX())
                player.persistentData.warpwave.y = Math.floor(player.getY())
                player.persistentData.warpwave.z = Math.floor(player.getZ())
                player.persistentData.warpwave.dim = player.getLevel().getDimension().toString()
                player.sendSystemMessage('§aLoaded!')
                createui(player)
            }
        })
        // Save Button
        gui.slot(8, 0, slot => {
            slot.item = Item.of(
                'minecraft:red_bed',
                1,
                createItemNBT(
                    { text: "Save Waypoint", color: "red", bold: true, italic: false },
                    []
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave[`way${player.persistentData.warpwave.active}`].x = player.persistentData.warpwave.x
                player.persistentData.warpwave[`way${player.persistentData.warpwave.active}`].y = player.persistentData.warpwave.y
                player.persistentData.warpwave[`way${player.persistentData.warpwave.active}`].z = player.persistentData.warpwave.z
                player.persistentData.warpwave[`way${player.persistentData.warpwave.active}`].dim = player.persistentData.warpwave.dim
                player.sendSystemMessage('§aSaved!')
                createui(player)
            }
        })
        
        // X Series
        gui.slot(0, 2, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"X: -10","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x -= 10
                createui(player)
            }
        })
        gui.slot(0, 3, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"X: -100","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x -= 100
                createui(player)
            }
        })
        gui.slot(0, 4, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"X: -1000","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x -= 1000
                createui(player)
            }
        })
        gui.slot(2, 2, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"X: +10","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x += 10
                createui(player)
            }
        })
        gui.slot(2, 3, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"X: +100","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x += 100
                createui(player)
            }
        })
        gui.slot(2, 4, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"X: +1000","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.x += 1000
                createui(player)
            }
        })


        // Y Series
        gui.slot(3, 2, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"Y: -10","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.y -= 10
                createui(player)
            }
        })
        gui.slot(3, 3, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"Y: -100","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.y -= 100
                createui(player)
            }
        })
        gui.slot(3, 4, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"Y: -1000","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.y -= 1000
                createui(player)
            }
        })
        gui.slot(5, 2, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"Y: +10","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.y += 10
                createui(player)
            }
        })
        gui.slot(5, 3, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"Y: +100","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.y += 100
                createui(player)
            }
        })
        gui.slot(5, 4, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"Y: +1000","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.y += 1000
                createui(player)
            }
        })


        // Z Series
        gui.slot(6, 2, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"Z: -10","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.z -= 10
                createui(player)
            }
        })
        gui.slot(6, 3, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"Z: -100","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.z -= 100
                createui(player)
            }
        })
        gui.slot(6, 4, slot => {
            slot.item = Item.of(
                'minecraft:coal_block',
                1,
                {display:{Name:'["",{"text":"Z: -1000","italic":false,"color":"red"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.z -= 1000
                createui(player)
            }
        })
        gui.slot(8, 2, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"Z: +10","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.z += 10
                createui(player)
            }
        })
        gui.slot(8, 3, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"Z: +100","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.z += 100
                createui(player)
            }
        })
        gui.slot(8, 4, slot => {
            slot.item = Item.of(
                'minecraft:emerald_block',
                1,
                {display:{Name:'["",{"text":"Z: +1000","italic":false,"color":"green"}]'}}
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.z += 1000
                createui(player)
            }
        })


        gui.slot(2, 5, slot => {
            let regItem = 'minecraft:quartz_block'
            if (player.persistentData.warpwave.active == 1) {regItem = 'minecraft:emerald_block'}
            slot.item = Item.of(
                regItem,
                1,
                createItemNBT(
                    { text: "Waypoint 1", color: "white", bold: false, italic: false },
                    [
                        { text: ``, color: "white", bold: false, italic: false },
                        { text: `X: ${player.persistentData.warpwave.way1.x}`, color: "white", bold: false, italic: false },
                        { text: `Y: ${player.persistentData.warpwave.way1.y}`, color: "white", bold: false, italic: false },
                        { text: `Z: ${player.persistentData.warpwave.way1.z}`, color: "white", bold: false, italic: false },
                        { text: `#: ${player.persistentData.warpwave.way1.dim}`, color: "white", bold: false, italic: false }
                    ]
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.active = 1
                player.persistentData.warpwave.x = player.persistentData.warpwave.way1.x
                player.persistentData.warpwave.y = player.persistentData.warpwave.way1.y
                player.persistentData.warpwave.z = player.persistentData.warpwave.way1.z
                player.persistentData.warpwave.dim = player.persistentData.warpwave.way1.dim
                createui(player)
            }
        })
        gui.slot(3, 5, slot => {
            let regItem = 'minecraft:quartz_block'
            if (player.persistentData.warpwave.active == 2) {regItem = 'minecraft:emerald_block'}
            slot.item = Item.of(
                regItem,
                1,
                createItemNBT(
                    { text: "Waypoint 2", color: "white", bold: false, italic: false },
                    [
                        { text: ``, color: "white", bold: false, italic: false },
                        { text: `X: ${player.persistentData.warpwave.way2.x}`, color: "white", bold: false, italic: false },
                        { text: `Y: ${player.persistentData.warpwave.way2.y}`, color: "white", bold: false, italic: false },
                        { text: `Z: ${player.persistentData.warpwave.way2.z}`, color: "white", bold: false, italic: false },
                        { text: `#: ${player.persistentData.warpwave.way2.dim}`, color: "white", bold: false, italic: false }
                    ]
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.active = 2
                player.persistentData.warpwave.x = player.persistentData.warpwave.way2.x
                player.persistentData.warpwave.y = player.persistentData.warpwave.way2.y
                player.persistentData.warpwave.z = player.persistentData.warpwave.way2.z
                player.persistentData.warpwave.dim = player.persistentData.warpwave.way2.dim
                createui(player)
            }
        })
        gui.slot(4, 5, slot => {
            let regItem = 'minecraft:quartz_block'
            if (player.persistentData.warpwave.active == 3) {regItem = 'minecraft:emerald_block'}
            slot.item = Item.of(
                regItem,
                1,
                createItemNBT(
                    { text: "Waypoint 3", color: "white", bold: false, italic: false },
                    [
                        { text: ``, color: "white", bold: false, italic: false },
                        { text: `X: ${player.persistentData.warpwave.way3.x}`, color: "white", bold: false, italic: false },
                        { text: `Y: ${player.persistentData.warpwave.way3.y}`, color: "white", bold: false, italic: false },
                        { text: `Z: ${player.persistentData.warpwave.way3.z}`, color: "white", bold: false, italic: false },
                        { text: `#: ${player.persistentData.warpwave.way3.dim}`, color: "white", bold: false, italic: false }
                    ]
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.active = 3
                player.persistentData.warpwave.x = player.persistentData.warpwave.way3.x
                player.persistentData.warpwave.y = player.persistentData.warpwave.way3.y
                player.persistentData.warpwave.z = player.persistentData.warpwave.way3.z
                player.persistentData.warpwave.dim = player.persistentData.warpwave.way3.dim
                createui(player)
            }
        })
        gui.slot(5, 5, slot => {
            let regItem = 'minecraft:quartz_block'
            if (player.persistentData.warpwave.active == 4) {regItem = 'minecraft:emerald_block'}
            slot.item = Item.of(
                regItem,
                1,
                createItemNBT(
                    { text: "Waypoint 4", color: "white", bold: false, italic: false },
                    [
                        { text: ``, color: "white", bold: false, italic: false },
                        { text: `X: ${player.persistentData.warpwave.way4.x}`, color: "white", bold: false, italic: false },
                        { text: `Y: ${player.persistentData.warpwave.way4.y}`, color: "white", bold: false, italic: false },
                        { text: `Z: ${player.persistentData.warpwave.way4.z}`, color: "white", bold: false, italic: false },
                        { text: `#: ${player.persistentData.warpwave.way4.dim}`, color: "white", bold: false, italic: false }
                    ]
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.active = 4
                player.persistentData.warpwave.x = player.persistentData.warpwave.way4.x
                player.persistentData.warpwave.y = player.persistentData.warpwave.way4.y
                player.persistentData.warpwave.z = player.persistentData.warpwave.way4.z
                player.persistentData.warpwave.dim = player.persistentData.warpwave.way4.dim
                createui(player)
            }
        })
        gui.slot(6, 5, slot => {
            let regItem = 'minecraft:quartz_block'
            if (player.persistentData.warpwave.active == 5) {regItem = 'minecraft:emerald_block'}
            slot.item = Item.of(
                regItem,
                1,
                createItemNBT(
                    { text: "Waypoint 5", color: "white", bold: false, italic: false },
                    [
                        { text: ``, color: "white", bold: false, italic: false },
                        { text: `X: ${player.persistentData.warpwave.way5.x}`, color: "white", bold: false, italic: false },
                        { text: `Y: ${player.persistentData.warpwave.way5.y}`, color: "white", bold: false, italic: false },
                        { text: `Z: ${player.persistentData.warpwave.way5.z}`, color: "white", bold: false, italic: false },
                        { text: `#: ${player.persistentData.warpwave.way5.dim}`, color: "white", bold: false, italic: false }
                    ]
                )
            )
            slot.leftClicked = (e) => {
                player.persistentData.warpwave.active = 5
                player.persistentData.warpwave.x = player.persistentData.warpwave.way5.x
                player.persistentData.warpwave.y = player.persistentData.warpwave.way5.y
                player.persistentData.warpwave.z = player.persistentData.warpwave.way5.z
                player.persistentData.warpwave.dim = player.persistentData.warpwave.way5.dim
                createui(player)
            }
        })
    })
}

StartupEvents.registry('sound_event', event => {
    event.create('arrzenhanced:warpwave_manipulation.open_breach')
    event.create('arrzenhanced:warpwave_manipulation.exit_breach')
    event.create('arrzenhanced:warpwave_manipulation.concussive_loop')
    event.create('arrzenhanced:warpwave_manipulation.open_boom_tube')
})