import { world, system, BlockPermutation, Player, ItemStack } from "@minecraft/server";
import { ActionFormData, ModalFormData, MessageFormData, uiManager } from "@minecraft/server-ui";
import { savePlayerXpLevel } from "./functions";
import { loadPlayerXpLevel } from "./functions";
import { getItemCount } from "./functions";
import { removeItems } from "./functions";
import { playAnimation } from "./functions";
import { activeBeacons } from "./beacon_particle";
/**
 *  Variables
 */
const alreadyRevivingNotified = new Map();
const formOpenFlags = new Map();
const deathTimers = new Map();
const triggeredPlayers = new Set();
const deathTimeouts = new Map();
const deathWarnings = new Map();
const revivingPlayers = new Set();
const deathCount = new Map();
const playersToShowForm = new Set();
let revive_time;
let revival_time;
let rawRevivalTime;
let revive_coordinates;
let revive_actionbar;
let revive_animation;
let rawTime;
let reviveTime_animation;
let revive_material;
let reviveCost;
let rawMaterial;
let revive_cost_quantity;
let revive_particle;
let death_beacon;
let frameIntervalId;
const timeMap = {
    "30s": 30,
    "2min": 120,
    "3min": 180,
    "5min": 300,
    "10min": 600,
    "15min": 900
};
const revivalMap = {
    "Instant": 0,
    "5s": 5,
    "10s": 10,
    "15s": 15,
    "30s": 30,
    "1min": 60
};
const timeMapLong = {
    "30s": "30 seconds",
    "2min": "2 minutes",
    "3min": "3 minutes",
    "5min": "5 minutes",
    "10min": "10 minutes",
    "15min": "15 minutes"
};
const timeMapAnimation = {
    "Risen": 3,
    "Slow Awakening": 4.5,
    "Superman": 6,
    "Happy Dance": 5.2,
    "Thank You": 3.5,
    "Flip": 3.2
};
const reviveActionbar = {
    "To all online players": 0, "To no one": 1, "To players within 100 blocks": 2
};
const materialMap = {
    "Coal": "minecraft:coal",
    "Lapis Lazuli": "minecraft:lapis_lazuli",
    "Redstone": "minecraft:redstone",
    "Copper": "minecraft:copper_ingot",
    "Iron Ingot": "minecraft:iron_ingot",
    "Gold Ingot": "minecraft:gold_ingot",
    "Diamond": "minecraft:diamond",
    "Emerald": "minecraft:emerald",
    "Netherite Scrap": "minecraft:netherite_scrap",
    "Netherite": "minecraft:netherite_ingot",
    "Enchanted Golden Apple": "minecraft:enchanted_golden_apple",
    "Totem Of Undying": "minecraft:totem_of_undying"
};
const itemColors = {
    "minecraft:coal": "§8",
    "minecraft:lapis_lazuli": "§9",
    "minecraft:redstone": "§c",
    "minecraft:copper_ingot": "§6",
    "minecraft:iron_ingot": "§f",
    "minecraft:gold_ingot": "§e",
    "minecraft:diamond": "§b",
    "minecraft:emerald": "§a",
    "minecraft:netherite_scrap": "§7",
    "minecraft:netherite_ingot": "§8",
    "minecraft:enchanted_golden_apple": "§d",
    "minecraft:totem_of_undying": "§2"
};


/**
 * Loop for checking player's health and intercepting the deaths
 */
system.runInterval(() => {
    rawTime = world.getDynamicProperty("revive_time");
    if (rawTime === undefined) {
        rawTime = "30s";
    }
    revive_time = timeMap[rawTime];

    reviveCost = world.getDynamicProperty("revive_cost");
    if (reviveCost === undefined) {
        reviveCost = false;
    }
    rawMaterial = world.getDynamicProperty("revive_cost_material");
    if (rawMaterial === undefined) {
        rawMaterial = "Coal";
    }
    revive_material = materialMap[rawMaterial];

    revive_cost_quantity = world.getDynamicProperty("revive_cost_quantity");
    if (revive_cost_quantity === undefined) {
        revive_cost_quantity = 1;
    }

    rawRevivalTime = world.getDynamicProperty("revival_time");
    if (rawRevivalTime === undefined) {
        rawRevivalTime = "5s";
    }
    revival_time = revivalMap[rawRevivalTime];


    revive_coordinates = world.getDynamicProperty("revive_coordinates");
    if (revive_coordinates === undefined) {
        revive_coordinates = true;
    }
    revive_actionbar = world.getDynamicProperty("revive_actionbar");
    if (revive_actionbar === undefined) {
        revive_actionbar = "To players within 100 blocks";
    }

    revive_animation = world.getDynamicProperty("revive_animation");
    if (revive_animation === undefined) {
        revive_animation = "Risen";
    }
    reviveTime_animation = timeMapAnimation[revive_animation]

    revive_particle = world.getDynamicProperty("revive_particle");
    if (revive_particle === undefined) {
        revive_particle = "Halo";
    }
    death_beacon = world.getDynamicProperty("death_beacon");
    if (death_beacon === undefined) {
        world.setDynamicProperty("death_beacon", true);
    }

    for (const player of world.getPlayers()) {
        const healthComp = player.getComponent("health");
        const id = player.id;
        if (!healthComp) continue;

        const currentHealth = healthComp.currentValue;



        if (isPlayerLoggedOut(player)) {

            return;
        }
       
        if (currentHealth < 5 && !triggeredPlayers.has(player.id) && !isPlayerLoggedOut(player)) {
            if (player.getDynamicProperty("void_damage_received")) {
                player.runCommand("camera @s fade time 0.1 0.5 0.5")
                if (player.getDynamicProperty("cbcl_rm:player_revived")) {
                    player.setDynamicProperty("cbcl_rm:force_void_kill", true);
                    player.runCommand("gamerule doimmediaterespawn false");
                    player.runCommand("gamerule keepInventory false");
                    return;

                }
                player.runCommand("gamerule doimmediaterespawn false");
                handleReviveChoiceVoid(player);
                return;
            }
        }
        if (currentHealth < 0.5 && !triggeredPlayers.has(player.id) && !isPlayerLoggedOut(player)) {
            triggeredPlayers.add(player.id);
            player.setDynamicProperty("cbcl_rm:dead", false);
            player.runCommand("title @s times 0 20 20")
            player.runCommand("hud @s hide");
            player.runCommand("playanimation @s animation.cbcl_rm.player_scale")
            player.runCommand("camera @s fade time 0.1 1.5 1");
            player.runCommand("tp @s ~ ~ ~");
            if (!revivingPlayers.has(id)) {
                player.setDynamicProperty("cbcl_rm:actionbar", true);
                player.runCommand("title @s title §c§lYOU DIED!")
                savePlayerXpLevel(player);
                //    saveHotbar(player)
                player.setDynamicProperty("cbcl_rm:dead", true);
                player.addEffect("minecraft:resistance", 1200, { "amplifier": 255, "showParticles": false });
                lockPlayerSlot(player);
                showForm(player);
                system.runTimeout(() => {
                    knockbackNearbyEntities(player)
                    //  knockbackNearbyEntitiesAll(player)
                }, 5)
                const intervalId = system.runInterval(() => {
                    const deadState = player.getDynamicProperty("cbcl_rm:dead_state");

                    if (deadState) {
                        spawnTaggedEntity(player);
                        system.clearRun(intervalId);
                    }
                }, 10);
            }
        }

        if (currentHealth >= 1 && triggeredPlayers.has(player.id) && !isPlayerLoggedOut(player)) {
            triggeredPlayers.delete(player.id);
        }
    }
}, 1);
/**
 * Set player's spawnpoint on bed
 */

world.afterEvents.playerInteractWithBlock.subscribe(event => {
    const player = event.player;
    const block = event.block;


    if (block.typeId.includes("bed")) {
        const bedPos = block.location;
        const spawnPos = {
            x: Math.floor(bedPos.x),
            y: Math.floor(bedPos.y) + 1,
            z: Math.floor(bedPos.z),
        };

        player.setDynamicProperty("bedSpawnpoint", JSON.stringify(spawnPos));

    }
});

/**
 * Update player's spawnpoint each 5 ticks
 */
function spawnpoint(player) {
    const id = player.id;
    const interval = system.runInterval(() => {
        try {
            if (player.getDynamicProperty("cbcl_rm:player_spawnpoint")) return;
            if (!revivingPlayers.has(id)) {

                player.runCommand("spawnpoint @s ~ ~ ~");
            } else {
                system.clearRun(interval);
            }
        }
        catch (e) { }
    }, 1);
}
/**
 * Disable breaking blocks while dead
 */
world.beforeEvents.playerBreakBlock.subscribe((event) => {
    const player = event.player;
    const id = player.id;

    if (revivingPlayers.has(id)) {
        event.cancel = true;
    }
});
/**
 * Mechanic for making player look dead
 */
world.afterEvents.playerSpawn.subscribe((event) => {
    const player = event.player;
    const id = player.id;

    if (isPlayerLoggedOut(player)) {
        return;
    }
    if (player.getDynamicProperty("cbcl_rm:force_void_kill")) {

        player.setDynamicProperty("cbcl_rm:force_void_kill", false);
        system.runTimeout(() => {
            player.setDynamicProperty("cbcl_rm:player_spawnpoint", true)
            player.setDynamicProperty("cbcl_rm:player_revived", false);
            forceDeath(player);
        }, 1);
        return;
    }
    if (player.getDynamicProperty("void_damage_received")) {

        player.setDynamicProperty("void_damage_received", false);
        player.setDynamicProperty("cbcl_rm:player_spawnpoint", false)
        player.runCommand("gamerule doimmediaterespawn true");

        spawnpoint(player);
        return;
    }

    player.setDynamicProperty("cbcl_rm:player_spawnpoint", false)
    player.runCommand("gamerule keepInventory true");
    if (event.initialSpawn) {
        player.setDynamicProperty("cbcl_rm:dead", false)
        player.runCommand("gamerule doimmediaterespawn true");
        player.runCommand("gamerule keepInventory true");
        player.runCommand("gamerule showdeathmessages false")
        player.runCommand("gamerule sendcommandfeedback false")
        if (!player.getDynamicProperty("defaultSpawnpoint")) {
            const { x, y, z } = player.location;
            const spawnData = { x: Math.floor(x), y: Math.floor(y), z: Math.floor(z) };

            player.setDynamicProperty("defaultSpawnpoint", JSON.stringify(spawnData));
        }

        spawnpoint(player);
        return;
    }

    if (revivingPlayers.has(id)) {

        const deaths = deathCount.get(id) || 0;

        if (deaths < 1) {
            deathCount.set(id, deaths + 1);
            return;
        }
        revivingPlayers.delete(id);
        deathCount.delete(id);
        let spawnpointData = player.getDynamicProperty("bedSpawnpoint") || player.getDynamicProperty("defaultSpawnpoint");
        const coords = JSON.parse(spawnpointData);
        player.runCommand(`tp @s ${coords.x} ${coords.y + 0.5} ${coords.z}`);
        player.runCommand("inputpermission set @s camera enabled");
        player.runCommand("inputpermission set @s movement enabled");
        player.runCommand("hud @s reset");
        player.runCommand("camera @s clear");
        player.runCommand("playanimation @s animation.cbcl_rm.player_alive");
        player.runCommand("xp -100l @s")
        system.runTimeout(() => {
            player.runCommand("inputpermission set @s camera enabled");
            player.runCommand("inputpermission set @s movement enabled");
            player.runCommand("gamerule keepinventory true")
            player.runCommand("hud @s reset");
            player.runCommand("camera @s clear");
            player.runCommand("playanimation @s animation.cbcl_rm.player_alive");
            player.runCommand("gamerule doimmediaterespawn true");
            spawnpoint(player);
        }, 40);


        try {
            system.clearRun(deathTimeouts.get(id));
            system.clearRun(deathWarnings.get(id));
            deathTimeouts.delete(id);
            deathWarnings.delete(id);
        }
        catch (e) { }
        player.runCommand("gamerule keepInventory true");

        return;
    }

    spawnpoint(player);
    const playerName = player.name;
    const pos = player.location;
    const coords = `X:${pos.x.toFixed(1)} Y:${pos.y.toFixed(1)} Z:${pos.z.toFixed(1)}`;

    const dimensionId = player.dimension.id;

    let message;
    switch (revive_coordinates) {
        case true:
            if (dimensionId === "minecraft:overworld") {
                message = `§c${playerName} died at ${coords} and they have ${timeMapLong[rawTime]} to be revived!`;
            } else if (dimensionId === "minecraft:nether") {
                message = `§c${playerName} died at ${coords} in the Nether and they have ${timeMapLong[rawTime]} to be revived!`;
            } else if (dimensionId === "minecraft:the_end") {
                message = `§c${playerName} died at ${coords} in the End and they have ${timeMapLong[rawTime]} to be revived!`;
            } else {
                message = `§c${playerName} died at ${coords} and they have ${timeMapLong[rawTime]} to be revived!`;
            }
            break;
        case false:
            if (dimensionId === "minecraft:overworld") {
                message = `§c${playerName} died and they have ${timeMapLong[rawTime]} to be revived!`;
            } else if (dimensionId === "minecraft:nether") {
                message = `§c${playerName} died and they have ${timeMapLong[rawTime]} to be revived!`;
            } else if (dimensionId === "minecraft:the_end") {
                message = `§c${playerName} died and they have ${timeMapLong[rawTime]} to be revived!`;
            } else {
                message = `§c${playerName} died and they have ${timeMapLong[rawTime]} to be revived!`;
            }
            break;
    }

    player.runCommand(`tellraw @a {"rawtext":[{"text":"${message}"}]}`);
    player.runCommand("gamerule doimmediaterespawn true");
    player.runCommand("tp @s ~ ~ ~ facing ~ ~ ~-5");

    player.playAnimation("animation.cbcl_rm.player_dead", { blendOutTime: 1 });
    playAnimation(player);
    player.setDynamicProperty("cbcl_rm:dead_state", true);
    system.runTimeout(() => {
        try {
            player.runCommand("effect @s water_breathing infinite 255 true")
        }
        catch (e) { }
    }, 20);
    system.runTimeout(() => {
        try {
            playCameraSequence(player)
        }
        catch (e) { }
    }, 15);
    system.runTimeout(() => {
        try {
            if (!player.getDynamicProperty("cbcl_rm:dead")) return;
            // showReviveForm(player);
            player.runCommand("title @s reset")
        }
        catch (e) { }
    }, 80);
    player.runCommand("stopsound @s")
    player.runCommand("inputpermission set @s camera disabled");
    player.runCommand("inputpermission set @s movement disabled");
    revivingPlayers.add(id);
    deathCount.set(id, 0);
    player.runCommand("effect @s resistance infinite 255 true")
    system.runTimeout(() => {
        try {
            startDeathTimer(player, revive_time)
        }
        catch (e) { }
    }, 15);


});
function startDeathTimer(player, remainingTimeSec, startFrame = 0) {
    const id = player.id;

    const old = deathTimers.get(id);
    if (old) {
        if (typeof old.warningTimeout === "number") system.clearRun(old.warningTimeout);
        if (typeof old.deathTimeout === "number") system.clearRun(old.deathTimeout);
        if (typeof old.frameIntervalId === "number") system.clearRun(old.frameIntervalId);
    }

    const warningSentAlready = old?.warningSent || false;
    const startTime = Date.now();

    deathTimers.set(id, {
        warningTimeout: null,
        deathTimeout: null,
        frameIntervalId: null,
        startTime,
        remainingTime: remainingTimeSec,
        warningSent: warningSentAlready,
        currentFrame: startFrame,
        totalFrames: 30
    });

    const timerData = deathTimers.get(id);

    if (remainingTimeSec > 10) {
        const warningDelay = 20 * (remainingTimeSec - 10);
        timerData.warningTimeout = system.runTimeout(() => {
            try {
                if (!player || !player.isValid) return;
                if (!player.getDynamicProperty("cbcl_rm:dead")) return;

                if (revivingPlayers.has(id)) {
                    player.runCommand(`tellraw @s {"rawtext":[{"text":"§cYou will die in 10s"}]}`);
                    timerData.warningSent = true;
                }
            } catch (e) {
            }
        }, warningDelay);
    }

    timerData.deathTimeout = system.runTimeout(() => {
        try {
            if (!player || !player.isValid) return;
            if (!player.getDynamicProperty("cbcl_rm:dead")) return;

            for (const p of world.getPlayers()) {
                try {
                    if (p.getDynamicProperty("cbcl_rm:revive_operator") === player.id) {
                        uiManager.closeAllForms(p);
                    }
                } catch (e) { }
            }

            handleReviveChoice(player);
            forceCloseForm(player);
            world.sendMessage(`§eNo one revived ${player.name} in time and they died.`);

            const interactEntity = world.getDimension(player.dimension.id)
                .getEntities({
                    location: player.location,
                    maxDistance: 5,
                    type: "cbcl_rm:interact_dummy"
                })
                .find(e => e.hasTag(player.id));

            if (interactEntity) {
                for (let i = timerData.currentFrame; i < timerData.totalFrames; i++) {
                    try { interactEntity.runCommand("event entity @s cbcl_rm:update_frame"); } catch (e) { }
                }
            }
        } catch (e) {
        }
    }, 20 * remainingTimeSec);

    let interactEntity;
    try {
        interactEntity = world.getDimension(player.dimension.id)
            .getEntities({
                location: player.location,
                maxDistance: 5,
                type: "cbcl_rm:interact_dummy"
            })
            .find(e => e.hasTag(player.id));
    } catch (e) {
        interactEntity = null;
    }

    if (!interactEntity) return;

    let currentFrame = startFrame;
    const totalFrames = timerData.totalFrames;
    const framesLeft = totalFrames - currentFrame;
    const frameInterval = Math.floor((timerData.remainingTime * 20) / framesLeft);

    timerData.frameIntervalId = system.runInterval(() => {
        try {
            if (!player || !player.isValid) {
                system.clearRun(timerData.frameIntervalId);
                return;
            }

            if (!player.getDynamicProperty("cbcl_rm:dead")) {
                system.clearRun(timerData.frameIntervalId);
                return;
            }

            if (currentFrame >= totalFrames) {
                system.clearRun(timerData.frameIntervalId);
                return;
            }

            try { interactEntity?.runCommand("event entity @s cbcl_rm:update_frame"); } catch (e) { }

            currentFrame++;
            timerData.currentFrame = currentFrame;
        } catch (e) {
            system.clearRun(timerData.frameIntervalId);
        }
    }, frameInterval);

    deathTimers.set(id, timerData);
}


function pauseDeathTimer(player) {
    const id = player.id;
    const timerData = deathTimers.get(id);
    if (!timerData) return;

    if (typeof timerData.warningTimeout === "number") system.clearRun(timerData.warningTimeout);
    if (typeof timerData.deathTimeout === "number") system.clearRun(timerData.deathTimeout);
    if (typeof timerData.frameIntervalId === "number") system.clearRun(timerData.frameIntervalId);

    const elapsed = (Date.now() - timerData.startTime) / 1000;
    timerData.remainingTime = Math.max(timerData.remainingTime - elapsed, 0);
    timerData.startTime = Date.now();

    deathTimers.set(id, timerData);
}

function resumeDeathTimer(player) {
    const id = player.id;
    const timerData = deathTimers.get(id);
    if (!timerData) return;

    startDeathTimer(player, timerData.remainingTime, timerData.currentFrame);
}

/**
 * 
 * Form that lets player choose to Die 
 */
function showReviveForm(player) {
    const id = player.id;
    const form = new ActionFormData()
        .title("Revive")
        .body(`You died. You have ${timeMapLong[rawTime]} to be revived by another player.`)
        .button("Give Up", "textures/cbcl/rm/icons/skull")         // index 0
        .button("Close Menu", "textures/cbcl/rm/icons/close_menu"); // index 1

    form.show(player).then(response => {
        if (response.canceled) {
            player.runCommand("title @s actionbar §c§lINTERACT to open menu");
            return;
        }

        if (response.selection === 1) {
            return;
        }

        handleReviveChoice(player);
    });
}


/**
 * 
 * Form that lets player chose to Die
 */
function handleReviveChoice(player) {
    const id = player.id;
    player.setDynamicProperty("cbcl_rm:actionbar", false);
    revivingPlayers.add(id);
    deathCount.set(id, 0);
    player.runCommand("camera @s fade time 0.1 1.5 1");

    player.runCommand("gamerule doimmediaterespawn false");

    system.runTimeout(() => {

        player.runCommand("kill @s");

        //  player.runCommand("xp -100l @s")
        system.runTimeout(() => {
            player.runCommand("gamerule keepInventory false");
            player.runCommand("stopsound @a");
            let spawnpointData = player.getDynamicProperty("bedSpawnpoint") || player.getDynamicProperty("defaultSpawnpoint");

            const processRespawn = (x = 100, y = 0, z = 100) => {
                const dimension = player.dimension.id;

                if (dimension === "minecraft:nether" || dimension === "minecraft:the_end") {
                    player.runCommand("clearspawnpoint @s");
                } else {
                    player.runCommand(`spawnpoint @s ${x} ${y} ${z}`);
                }

                system.runTimeout(() => {

                    player.runCommand("stopsound @a");
                    player.runCommand("kill @s");
                    player.runCommand("gamemode spectator")
                    player.runCommand("stopsound @a");
                    player.runCommand("inputpermission set @s camera enabled");
                    player.runCommand("inputpermission set @s movement enabled");
                    player.runCommand("hud @s reset");
                    player.setDynamicProperty("cbcl_rm:dead", false);
                    player.runCommand("camera @s clear");
                    player.runCommand("playanimation @s animation.cbcl_rm.player_alive");
                    player.runCommand(`event entity @e[type=cbcl_rm:interact_dummy,tag="${id}"] cbcl_rm:despawn`);
                    system.runTimeout(() => { player.runCommand("gamemode survival") }, 10);

                    try {
                        triggeredPlayers.delete(player.id);
                        const deathTimeoutId = deathTimeouts.get(id);
                        if (typeof deathTimeoutId === "number") {
                            system.clearRun(deathTimeoutId);
                        }

                        const deathWarningId = deathWarnings.get(id);
                        if (typeof deathWarningId === "number") {
                            system.clearRun(deathWarningId);
                        }
                        deathTimeouts.delete(id);
                        deathWarnings.delete(id);
                    } catch (e) {
                        console.warn(e);
                    }
                }, 1);
            };

            if (spawnpointData) {
                try {
                    const coords = JSON.parse(spawnpointData);
                    processRespawn(coords.x, coords.y, coords.z);
                } catch {
                    processRespawn(); // fallback
                }
            } else {
                processRespawn(); // fallback
            }
        }, 10);
    }, 10);
}
function handleReviveChoice2(player) {
    const id = player.id;
    player.setDynamicProperty("cbcl_rm:actionbar", false);
    revivingPlayers.add(id);
    deathCount.set(id, 0);
    player.runCommand("camera @s fade time 0.1 1.5 1");
    player.runCommand("gamerule keepInventory false");
    player.runCommand("gamerule doimmediaterespawn false");

    system.runTimeout(() => {

        player.runCommand("kill @s");

        system.runTimeout(() => {
            player.runCommand("stopsound @a");
            let spawnpointData = player.getDynamicProperty("bedSpawnpoint") || player.getDynamicProperty("defaultSpawnpoint");

            const processRespawn = (x = 100, y = 0, z = 100) => {
                const dimension = player.dimension.id;

                if (dimension === "minecraft:nether" || dimension === "minecraft:the_end") {
                    player.runCommand("clearspawnpoint @s");
                } else {
                    player.runCommand(`spawnpoint @s ${x} ${y} ${z}`);
                }

                system.runTimeout(() => {
                    player.runCommand("stopsound @a");
                    player.runCommand("kill @s");
                    deathCount.set(id, 1);

                    player.runCommand("stopsound @a");
                    player.runCommand("inputpermission set @s camera enabled");
                    player.runCommand("inputpermission set @s movement enabled");
                    player.runCommand("hud @s reset");
                    player.setDynamicProperty("cbcl_rm:dead", false);
                    player.runCommand("camera @s clear");
                    player.runCommand("playanimation @s animation.cbcl_rm.player_alive");
                    player.runCommand(`event entity @e[type=cbcl_rm:interact_dummy,tag="${id}"] cbcl_rm:despawn`);
                    player.runCommand("gamerule keepInventory true");
                    let loggedOutPlayers = JSON.parse(world.getDynamicProperty("logged_out_players") || "[]");
                    loggedOutPlayers = loggedOutPlayers.filter(id => id !== player.id);
                    world.setDynamicProperty("logged_out_players", JSON.stringify(loggedOutPlayers));

                    try {
                        triggeredPlayers.delete(player.id);
                        const deathTimeoutId = deathTimeouts.get(id);
                        if (typeof deathTimeoutId === "number") {
                            system.clearRun(deathTimeoutId);
                        }

                        const deathWarningId = deathWarnings.get(id);
                        if (typeof deathWarningId === "number") {
                            system.clearRun(deathWarningId);
                        }
                        deathTimeouts.delete(id);
                        deathWarnings.delete(id);
                    } catch (e) {
                        console.warn(e);
                    }
                }, 1);
            };

            if (spawnpointData) {
                try {
                    const coords = JSON.parse(spawnpointData);
                    processRespawn(coords.x, coords.y, coords.z);
                } catch {
                    processRespawn(); // fallback
                }
            } else {
                processRespawn(); // fallback
            }
        }, 60);
    }, 60);
}
function handleReviveChoiceVoid(player) {
    const id = player.id;
    player.runCommand("gamerule doimmediaterespawn false");

    player.runCommand("gamerule keepInventory false");
    // player.setDynamicProperty("void_damage_received", false);
    system.runTimeout(() => {

        player.runCommand("gamerule keepInventory false");
        player.runCommand("stopsound @a");
        let spawnpointData = player.getDynamicProperty("bedSpawnpoint") || player.getDynamicProperty("defaultSpawnpoint");

        const processRespawn = (x = 100, y = 0, z = 100) => {
            player.runCommand("clearspawnpoint @s");

            system.runTimeout(() => {

                player.setDynamicProperty("cbcl_rm:dead", false);


            }, 1);
        };

        if (spawnpointData) {
            try {
                const coords = JSON.parse(spawnpointData);
                processRespawn(coords.x, coords.y, coords.z);
            } catch {
                processRespawn(); // fallback
            }
        } else {
            processRespawn(); // fallback
        }

    }, 10);
}
const fixedSlots = new Map();
const DEFAULT_SLOT = 0;

/**
 * 
 * Disables switching between slots
 */
function lockPlayerSlot(player) {
    system.runInterval(() => {


        try {
            if (!player.getDynamicProperty("cbcl_rm:dead")) return;
            const currentSlot = player.selectedSlotIndex;

            if (!fixedSlots.has(player.id)) {
                fixedSlots.set(player.id, DEFAULT_SLOT);
                player.selectedSlotIndex = DEFAULT_SLOT;
            }

            const fixedSlot = fixedSlots.get(player.id);

            if (currentSlot !== fixedSlot) {
                try {
                    player.selectedSlotIndex = fixedSlot;
                } catch (error) {

                }
            }
        } catch (error) {


        }
    }, 0);
}



world.beforeEvents.playerInteractWithBlock.subscribe((event) => {

    const player = event.player;
    if (!player.getDynamicProperty("cbcl_rm:dead")) return;
    event.cancel = true;

    playersToShowForm.add(player.id);
});
function showForm(player) {
    if (!player.getDynamicProperty("cbcl_rm:dead")) return;
    const id = player.id;
    world.beforeEvents.itemUse.subscribe((event) => {
        const eventPlayer = event.source;

        if (event.itemStack.typeId === "cbcl_rm:revive_settings") {
            if (!eventPlayer.getDynamicProperty("cbcl_rm:dead"))
                return;
        }

        if (revivingPlayers.has(eventPlayer.id)) {
            event.cancel = true;
        }
    });
    system.runInterval(() => {
        for (const playerId of playersToShowForm) {
            const player = world.getPlayers().find(p => p.id === playerId);
            if (player) {
                showReviveForm(player);
            }
        }
        playersToShowForm.clear();
    }, 1);
}

/**
 * 
 * Spawn entity that is detecting interactions
 */
function spawnTaggedEntity(player) {
    const location = { ...player.location };
    location.y += 0;
    location.z -= 1;

    const dimension = player.dimension;

    try {
        const entity = dimension.spawnEntity("cbcl_rm:interact_dummy", location);
        entity.addTag(player.id);
        /* system.runInterval(() => {
             try {
                 entity.teleport(player.location, player.dimension)
             } catch (e) {
 
             }
         }, 20);*/

    } catch (e) {

    }
}



/*
Revive Player
*/
world.afterEvents.playerInteractWithEntity.subscribe(event => {
    const player = event.player;
    const entity = event.target;

    if (!entity || entity.typeId !== "cbcl_rm:interact_dummy") return;
    try {
        const tags = entity.getTags();

        if (tags.length === 0) {

            return;
        }

        const targetPlayerId = tags[0];

        if (player.id === targetPlayerId) {
            showReviveForm(player);
            return;
        }

        const allPlayers = world.getPlayers();
        const targetPlayer = allPlayers.find(p => p.id === targetPlayerId);

        if (!targetPlayer) {
            return;
        }
    }
    catch (e) { }
});

function revivePlayer(player, entity) {
    player.setDynamicProperty("cbcl_rm:dead", false);
    const id = player.id;
    const head = player.getHeadLocation();
    const lookAt = {
        x: head.x,
        y: head.y,
        z: head.z
    };
    const backwardDir = {
        x: 0,
        y: 0,
        z: 1
    };
    const cameraStartHeightOffset = 0;
    const startPos = {
        x: lookAt.x + backwardDir.x * 4,
        y: lookAt.y + cameraStartHeightOffset,
        z: lookAt.z + backwardDir.z * 4
    };
    const easeBackPos = {
        x: lookAt.x + backwardDir.x * 8,
        y: lookAt.y + cameraStartHeightOffset + 1,
        z: lookAt.z + backwardDir.z * 8
    };
    const easeUpPos = {
        x: easeBackPos.x,
        y: easeBackPos.y + 2,
        z: easeBackPos.z
    };
    //player.runCommand("camera @s fade time 0.1 0.3 0.1");
    player.runCommand(
        `/camera @s set minecraft:free ease 3 in_out_sine pos ${easeUpPos.x.toFixed(2)} ${easeUpPos.y.toFixed(2)} ${easeUpPos.z.toFixed(2)} facing ${lookAt.x.toFixed(2)} ${lookAt.y.toFixed(2)} ${lookAt.z.toFixed(2)}`
    );

    forceCloseForm(player)
    player.runCommand("tp @s ~ ~ ~ facing ~ ~ ~5");
    player.runCommand(`/camera @s set minecraft:free pos ${easeUpPos.x.toFixed(2)} ${easeUpPos.y.toFixed(2)} ${easeUpPos.z.toFixed(2)} facing ${lookAt.x.toFixed(2)} ${lookAt.y.toFixed(2)} ${lookAt.z.toFixed(2)}`)
    player.setDynamicProperty("cbcl_rm:player_revived", true);
    switch (revive_particle) {
        case "Totem":
            player.runCommand("particle minecraft:huge_explosion_emitter ~ ~ ~");
            player.runCommand("particle minecraft:totem_particle ~ ~ ~");
            break;

        case "Halo":
            if (revive_animation === "Slow Awakening") {
                player.runCommand("particle cbcl_rm:revive_1 ~ ~ ~");
                player.runCommand("particle cbcl_rm:revive_2 ~ ~ ~");
                player.runCommand("particle cbcl_rm:revive_3 ~ ~ ~");
                player.runCommand("particle cbcl_rm:revive_4 ~ ~ ~");
            } else if (revive_animation === "Risen" || revive_animation === "Superman") {
                player.runCommand("particle cbcl_rm:revive_1_v2 ~ ~ ~");
                player.runCommand("particle cbcl_rm:revive_2_v2 ~ ~ ~");
                player.runCommand("particle cbcl_rm:revive_3_v2 ~ ~ ~");
                player.runCommand("particle cbcl_rm:revive_4_v2 ~ ~ ~");
            }

            break;
    }

    player.runCommand("playsound random.totem @a[r=5]")
    player.runCommand("playsound cbcl_rm:revive @a[r=5]")


    system.runTimeout(() => {
        const head = player.getHeadLocation();
        const lookAt = {
            x: head.x,
            y: head.y,
            z: head.z
        };
        const backwardDir = {
            x: 0,
            y: 0,
            z: 1
        };
        const cameraStartHeightOffset = 0;
        const startPos = {
            x: lookAt.x + backwardDir.x * 4,
            y: lookAt.y - 0.5,
            z: lookAt.z + backwardDir.z * 4
        };
        player.runCommand(`tp @s ~ ~ ~ facing ${startPos.x.toFixed(2)} ${startPos.y.toFixed(2)} ${startPos.z.toFixed(2)}`)

        player.runCommand("title @s title §a§lYou have been\n revived!")
        player.setDynamicProperty("cbcl_rm:player_spawnpoint", false)
        switch (revive_animation) {
            case "Risen":
                player.playAnimation("animation.cbcl_rm.player.risen", { blendOutTime: 1 });
                break;
            case "Slow Awakening":
                player.playAnimation("animation.cbcl_rm.player.slow_awakening", { blendOutTime: 1 });
                break;
            case "Superman":
                player.playAnimation("animation.cbcl_rm.player.superman", { blendOutTime: 1 });
                break;
            case "Thank You":
                player.playAnimation("animation.cbcl_rm.player.thank_you", { blendOutTime: 1 });
                break;
            case "Flip":
                player.playAnimation("animation.cbcl_rm.player.flip", { blendOutTime: 1 });
                break;
            case "Happy Dance":
                player.playAnimation("animation.cbcl_rm.player.kick_up", { blendOutTime: 1 });
                break;
        }

    }, 5);

    player.setDynamicProperty("cbcl_rm:dead_state", false);
    entity.runCommand("event entity @s cbcl_rm:despawn");

    loadPlayerXpLevel(player)
    revivingPlayers.delete(player.id);
    deathCount.delete(player.id);
    try {
        system.clearRun(deathTimeouts.get(id));
        system.clearRun(deathWarnings.get(id));
    } catch (e) { }
    deathTimeouts.delete(id);
    deathWarnings.delete(id);
    system.runTimeout(() => {
        player.runCommand("camera @s fade time 0.5 0.5 0.5");
    }, (20 * reviveTime_animation) - 10);
    system.runTimeout(() => {
        player.runCommand("hud @s reset");
        player.runCommand("effect @s clear")
        player.runCommand("camera @s clear");
        player.runCommand("inputpermission set @s camera enabled");
        player.runCommand("inputpermission set @s movement enabled");

        spawnpoint(player);
    }, 20 * reviveTime_animation);

}

function forceCloseForm(player) {
    system.run(() => {
        try {
            uiManager.closeAllForms(player);

        } catch (e) {

        }
    });
}
function playCameraSequence(player) {
    const head = player.getHeadLocation();
    const lookAt = {
        x: head.x,
        y: head.y,
        z: head.z
    };
    const backwardDir = {
        x: 0,
        y: 0,
        z: 1
    };
    const cameraStartHeightOffset = 0;
    const startPos = {
        x: lookAt.x + backwardDir.x * 4,
        y: lookAt.y + cameraStartHeightOffset,
        z: lookAt.z + backwardDir.z * 4
    };
    const easeBackPos = {
        x: lookAt.x + backwardDir.x * 8,
        y: lookAt.y + cameraStartHeightOffset + 1,
        z: lookAt.z + backwardDir.z * 8
    };
    const easeUpPos = {
        x: easeBackPos.x,
        y: easeBackPos.y + 2,
        z: easeBackPos.z
    };
    system.runTimeout(() => {
        player.runCommand(
            `/camera @s set minecraft:free pos ${startPos.x.toFixed(2)} ${startPos.y.toFixed(2)} ${startPos.z.toFixed(2)} facing ${lookAt.x.toFixed(2)} ${lookAt.y.toFixed(2)} ${lookAt.z.toFixed(2)}`
        );
    }, 0);
    system.runTimeout(() => {
        player.runCommand(
            `/camera @s set minecraft:free ease 3 in_out_sine pos ${easeUpPos.x.toFixed(2)} ${easeUpPos.y.toFixed(2)} ${easeUpPos.z.toFixed(2)} facing ${lookAt.x.toFixed(2)} ${lookAt.y.toFixed(2)} ${lookAt.z.toFixed(2)}`
        );
    }, 20);
    system.runTimeout(() => {
        player.runCommand("/camera @s fade time 0.5 0.5 0.5")
    }, 70);
    system.runTimeout(() => {
        player.runCommand("/inputpermission set @s camera enabled")
    }, 75);
    system.runTimeout(() => {
        player.camera.setCamera('minecraft:follow_orbit', { viewOffset: { x: 0, y: 1 } });
    }, 80);
}

function knockbackNearbyEntities(player) {
    try {
        const entities = player.dimension.getEntities({
            location: player.location,
            maxDistance: 5,
            excludeTypes: ["minecraft:player", "cbcl_rm:interact_dummy", "minecraft:item"]
        });

        for (const entity of entities) {
            const dx = entity.location.x - player.location.x;
            const dz = entity.location.z - player.location.z;
            const dist = Math.hypot(dx, dz);
            if (dist === 0) continue;

            entity.applyKnockback(dx / dist, dz / dist, 2, 0.5);
            //  entity.runCommand("say ouch")
        }
    } catch (e) { }
}

world.afterEvents.entityHurt.subscribe((event) => {
    const player = event.hurtEntity;

    if (player.typeId !== "minecraft:player") return;
    if (!player.getDynamicProperty("cbcl_rm:dead")) return;
    const oldPos = player.location;

    system.run(() => {
        player.teleport(oldPos, {
            keepVelocity: false
        });
    });
});

function teleportPlayer(player) {
    system.runInterval(() => {
        if (!player.getDynamicProperty("cbcl_rm:dead")) return;
        player.runCommand(`tp @s ${player.location.x} ${player.location.y} ${player.location.z}`)
    }, 1);

}

export function displayActionbar(player) {
    const id = player.id;
    if (!revivingPlayers.has(id)) return;
    if (!player.getDynamicProperty("cbcl_rm:actionbar")) return;

    const dimension = player.dimension;
    const reviverPos = player.location;

    if (player.getDynamicProperty("cbcl_rm:dead")) {
        player.runCommand("title @s actionbar §c§lINTERACT to open menu");
    }

    const globalMessage = "§cA player died! §f§lSNEAK §rnext to them to revive them";

    for (const otherPlayer of world.getPlayers()) {
        if (otherPlayer.id === id) continue;
        if (otherPlayer.dimension !== dimension) continue;

        if (otherPlayer.getDynamicProperty("cbcl_rm:dead")) {
            otherPlayer.runCommand("title @s actionbar §c§lINTERACT to open menu");
            continue;
        }

        const otherPos = otherPlayer.location;
        const dx = otherPos.x - reviverPos.x;
        const dy = otherPos.y - reviverPos.y;
        const dz = otherPos.z - reviverPos.z;
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);

        let showedProximityMessage = false;
        if (distance <= 5) {
            if (otherPlayer.isFlying) {
                otherPlayer.runCommand(`title @s actionbar §eYou cannot §lSNEAK§r§e while flying in creative!`);
            } else if (!otherPlayer.isSneaking) {
                otherPlayer.runCommand("title @s actionbar §a§lSNEAK§r§a to revive this player!");
            }
            showedProximityMessage = true;
        }

        if (!showedProximityMessage) {
            switch (revive_actionbar) {
                case "To all online players":
                    otherPlayer.runCommand(`title @s actionbar ${globalMessage}`);
                    break;

                case "To players within 100 blocks":
                    if (distance <= 100) {
                        otherPlayer.runCommand(`title @s actionbar ${globalMessage}`);
                    }
                    break;

                case "To no one":
                default:
                    // No global message
                    break;
            }
        }
    }
}



function getSneakHoldTime() {
    const raw = world.getDynamicProperty("revival_time") || "5s";
    const revivalMap = {
        "Instant": 0,
        "5s": 5,
        "10s": 10,
        "15s": 15,
        "30s": 30,
        "1min": 60
    };
    const seconds = revivalMap[raw] ?? 5;
    return seconds * 20;
}

const sneakTimers = new Map();

system.runInterval(() => {
    for (const player of world.getPlayers()) {
        const playerId = player.id;

        if (!player.isSneaking) {
            const timerData = sneakTimers.get(playerId);
            const inForm = formOpenFlags.get(playerId);
            if (timerData && !inForm) {
                const targetPlayer = world.getPlayers().find(p => p.id === timerData.entityId);
                if (targetPlayer) {
                    resumeDeathTimer(targetPlayer);
                    const interactEntity = world.getDimension(targetPlayer.dimension.id)
                        .getEntities({ location: targetPlayer.location, maxDistance: 5, type: "cbcl_rm:interact_dummy" })
                        .find(e => e.hasTag(targetPlayer.id));
                    if (interactEntity) {
                        try { interactEntity.runCommand("event entity @s cbcl_rm:revival_stop"); } catch (e) { }
                    }
                    targetPlayer.runCommand(`tellraw @s {"rawtext":[{"text":"§c${player.name} stopped reviving you!"}]}`);
                    player.runCommand(`tellraw @s {"rawtext":[{"text":"§cYou stopped reviving ${targetPlayer.name}!"}]}`);
                }
            }

            sneakTimers.delete(playerId);
            alreadyRevivingNotified.delete(playerId);
            continue;
        }

        const targetPlayer = getNearbyDeadPlayer(player, 5);
        if (!targetPlayer) {
            const timerData = sneakTimers.get(playerId);
            if (timerData) {
                const previousTarget = world.getPlayers().find(p => p.id === timerData.entityId);
                if (previousTarget) {
                    resumeDeathTimer(previousTarget);

                    const interactEntity = world.getDimension(previousTarget.dimension.id).getEntities({
                        location: previousTarget.location,
                        maxDistance: 5,
                        type: "cbcl_rm:interact_dummy"
                    }).find(e => e.hasTag(previousTarget.id));

                    if (interactEntity) {
                        try { interactEntity.runCommand("event entity @s cbcl_rm:revival_stop"); } catch (e) { }
                    }

                    previousTarget.runCommand(`tellraw @s {"rawtext":[{"text":"§c${player.name} stopped reviving you!"}]}`);
                    player.runCommand(`tellraw @s {"rawtext":[{"text":"§cYou stopped reviving ${previousTarget.name}!"}]}`);
                }
            }
            alreadyRevivingNotified.delete(playerId);
            sneakTimers.delete(playerId);
            continue;
        }

        const targetPlayerId = targetPlayer.id;
        const existingTimer = sneakTimers.get(playerId);
        const alreadyReviving = [...sneakTimers.entries()].some(([reviverId, timer]) =>
            timer.entityId === targetPlayerId && reviverId !== playerId
        );

        if (alreadyReviving) {

            if (!alreadyRevivingNotified.has(playerId)) {
                player.runCommand(`tellraw @s {"rawtext":[{"text":"§cSomeone is already reviving ${targetPlayer.name}!"}]}`);
                alreadyRevivingNotified.set(playerId, true);
            }
            continue;
        } else {
            alreadyRevivingNotified.delete(playerId);
        }
        if (!existingTimer || existingTimer.entityId !== targetPlayerId) {


            system.runTimeout(() => {
                pauseDeathTimer(targetPlayer);
            }, 15);

            sneakTimers.set(playerId, {
                ticks: 1,
                entityId: targetPlayerId,
            });
            const interactEntity = world.getDimension(targetPlayer.dimension.id)
                .getEntities({
                    location: targetPlayer.location,
                    maxDistance: 5,
                    type: "cbcl_rm:interact_dummy"
                })
                .find(e => e.hasTag(targetPlayer.id));
            const inForm = formOpenFlags.get(playerId);
            if (!inForm) {
                if (interactEntity) {
                    try { interactEntity.runCommand("event entity @s cbcl_rm:revival_start"); } catch (e) { }
                }
                player.runCommand(`tellraw @s {"rawtext":[{"text":"§aYou started reviving ${targetPlayer.name}."}]}`);
                targetPlayer.runCommand(`tellraw @s {"rawtext":[{"text":"§a${player.name} is reviving you."}]}`);
            }
            continue;
        }

        existingTimer.ticks++;

        const revivalTime = getRevivalTime();
        const frames = 30;

        if (revivalTime === 0) {
            const interactEntity = world.getDimension(targetPlayer.dimension.id).getEntities({
                location: targetPlayer.location,
                maxDistance: 5,
                type: "cbcl_rm:interact_dummy"
            }).find(e => e.hasTag(targetPlayer.id));

            if (interactEntity) {
                try { interactEntity.runCommand("event entity @s cbcl_rm:revival_complete"); } catch (e) { }
            }
        } else {
            const totalBars = 30;
            const revivalTicks = revivalTime * 20;
            const progress = Math.min(
                Math.floor((existingTimer.ticks / revivalTicks) * totalBars),
                totalBars
            );

            if (progress > (existingTimer.lastProgress ?? -1)) {
                existingTimer.lastProgress = progress;

                const interactEntity = world.getDimension(targetPlayer.dimension.id).getEntities({
                    location: targetPlayer.location,
                    maxDistance: 5,
                    type: "cbcl_rm:interact_dummy"
                }).find(e => e.hasTag(targetPlayer.id));

                if (interactEntity) {
                    player.playSound("block.itemframe.rotate_item");
                    try { interactEntity.runCommand("event entity @s cbcl_rm:update_frame_revival"); } catch (e) { }
                }
            }

            const filled = "§a|".repeat(progress);
            const empty = "§8|".repeat(totalBars - progress);

            player.runCommand(
                `titleraw @s actionbar {"rawtext":[{"text":"§a§lREVIVING! §r${filled}${empty}"}]}`
            );
        }

        if (existingTimer.ticks >= getSneakHoldTime()) {
            sneakTimers.delete(playerId);

            if (player.id === targetPlayerId) {
                showReviveForm(player);
                return;
            }

            const reviveEntity = getReviveEntityNearPlayer(targetPlayer);
            if (!reviveEntity) {
                //   player.runCommand(`tellraw @s {"rawtext":[{"text":"§cERROR! No revive entity found near ${targetPlayer.name}."}]}`);

                resumeDeathTimer(targetPlayer);
                continue;
            }

            if (reviveCost === true) {
                formOpenFlags.set(playerId, true);
                const itemColor = itemColors[revive_material] || "§f";
                const playerItemCount = getItemCount(player, revive_material);
                player.setDynamicProperty("cbcl_rm:revive_operator", targetPlayer.id);
                const form = new ActionFormData()
                    .title("Pay the price!")
                    .body(
                        `Reviving §r${targetPlayer.name}§r costs ${itemColor}${revive_cost_quantity} ${rawMaterial.toLowerCase()}§r.\n\n` +
                        `§rYou currently have: ${itemColor}${playerItemCount || 0} ${rawMaterial.toLowerCase()}§r.`
                    )
                    .button("Confirm & Pay", "textures/cbcl/rm/icons/pay_reviving")
                    .button("Stop Reviving", "textures/cbcl/rm/icons/stop_reviving");

                form.show(player).then(res => {
                    formOpenFlags.set(playerId, false);

                    if (res.canceled || res.selection === 1) {
                        resumeDeathTimer(targetPlayer);
                        player.runCommand(`tellraw @s {"rawtext":[{"text":"§cYou stopped reviving ${targetPlayer.name}!"}]}`);
                        sneakTimers.delete(playerId);
                        const interactEntity = world.getDimension(targetPlayer.dimension.id)
                            .getEntities({ location: targetPlayer.location, maxDistance: 5, type: "cbcl_rm:interact_dummy" })
                            .find(e => e.hasTag(targetPlayer.id));
                        if (interactEntity) {
                            try { interactEntity.runCommand("event entity @s cbcl_rm:revival_stop"); } catch (e) { }
                        }
                        return;
                    }

                    if (getItemCount(player, revive_material) < revive_cost_quantity) {
                        player.runCommand(`tellraw @s {"rawtext":[{"text":"§cYou don't have enough materials to revive!"}]}`);
                        resumeDeathTimer(targetPlayer);
                        sneakTimers.delete(playerId);
                        const interactEntity = world.getDimension(targetPlayer.dimension.id)
                            .getEntities({ location: targetPlayer.location, maxDistance: 5, type: "cbcl_rm:interact_dummy" })
                            .find(e => e.hasTag(targetPlayer.id));
                        if (interactEntity) {
                            try { interactEntity.runCommand("event entity @s cbcl_rm:revival_stop"); } catch (e) { }
                        }
                        return;
                    }

                    removeItems(player, revive_material, revive_cost_quantity);
                    world.sendMessage(`§a${targetPlayer.name} was successfully revived by ${player.name}`);

                    revivePlayer(targetPlayer, reviveEntity);

                }).catch(err => console.warn(err));

                continue;
            }

            world.sendMessage(`§a${targetPlayer.name} was successfully revived by ${player.name}`);


            revivePlayer(targetPlayer, reviveEntity);


        } else {
            sneakTimers.set(playerId, existingTimer);
        }
    }
}, 1);
function getRevivalTime() {

    return revival_time;
};

function getNearbyDeadPlayer(player, maxDistance = 3) {
    const playerPos = player.location;

    for (const other of world.getPlayers()) {
        if (other.id === player.id) continue;

        const otherPos = other.location;
        const dx = otherPos.x - playerPos.x;
        const dy = otherPos.y - playerPos.y;
        const dz = otherPos.z - playerPos.z;

        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);
        if (distance <= maxDistance) {
            const dead = other.getDynamicProperty("cbcl_rm:dead");
            const deadState = other.getDynamicProperty("cbcl_rm:dead_state");
            if ((dead === true || dead === 1 || dead === "true") && deadState) {
                return other;
            }
        }
    }

    return null;
}

function getReviveEntityNearPlayer(targetPlayer) {
    const allEntities = targetPlayer.dimension.getEntities();

    for (const entity of allEntities) {
        if (!entity.typeId || entity.typeId !== "cbcl_rm:interact_dummy") continue;

        const tags = entity.getTags();
        if (tags.includes(targetPlayer.id)) {
            return entity;
        }
    }

    return null;
}

system.afterEvents.scriptEventReceive.subscribe(eventData => {
    system.runTimeout(() => {
        const message = eventData.message;
        const entity = eventData.sourceEntity;
        if (!entity) {
            return;
        }

        if (message === "cbcl_rm:revive_reset") {
            revive_reset_all()
        }


    }, 10);
});
function revive_reset_all() {
    const players = world.getPlayers();

    for (const player of players) {
        const id = player.id;
        const entity = getReviveEntityNearPlayer(player);
        player.runCommand(`tellraw @s {"rawtext":[{"text":"§aRevive Add-On Reloaded"}]}`);
        player.setDynamicProperty("cbcl_rm:dead", false);
        player.runCommand("playanimation @s animation.cbcl_rm.player_alive");

        try {
            uiManager.closeAllForms(player);
            player.runCommand("gamemode survival");
            player.runCommand("hud @s reset");
            player.runCommand("effect @s clear");
            player.runCommand("camera @s clear");
            player.runCommand("gamerule doimmediaterespawn true");
            player.runCommand("gamerule keepInventory true");
            player.runCommand("inputpermission set @s camera enabled");
            player.runCommand("inputpermission set @s movement enabled");
            player.runCommand("event entity @e[type=cbcl_rm:interact_dummy] cbcl_rm:despawn");
            world.setDynamicProperty("logged_out_players", JSON.stringify([]));
            spawnpoint(player);
            system.runTimeout(() => {
                try {
                    entity.remove();
                } catch (e) { }
            }, 10);

            revivingPlayers.delete(id);
            deathCount.delete(id);

            const timeoutId = deathTimeouts.get(id);
            if (typeof timeoutId === "number") {
                system.clearRun(timeoutId);
                deathTimeouts.delete(id);
            } else {

            }

            const warningId = deathWarnings.get(id);
            if (typeof warningId === "number") {
                system.clearRun(warningId);
                deathWarnings.delete(id);
            } else {

            }
        } catch (e) {

        }
    }
}


world.beforeEvents.playerLeave.subscribe(event => {
    const player = event.player;

    let loggedOutPlayers = JSON.parse(world.getDynamicProperty("logged_out_players") || "[]");
    const revivePlayerId = world.getDynamicProperty("cbcl_rm_reviveSettingsPlayer");

    if (player.id === revivePlayerId) {
        const players = world.getPlayers();
        const overworld = world.getDimension("overworld");
        const beaconType = (world.getDynamicProperty("beacon_type") ?? "Red").toLowerCase();

        for (const p of players) {
            if (!p.isValid) continue;

            try {
                if (p.getDynamicProperty("cbcl_rm:dead") && !loggedOutPlayers.includes(p.id)) {
                    loggedOutPlayers.push(p.id);

                    for (const key of activeBeacons.keys()) {
                        if (key.startsWith(p.id + "_")) {
                            const beaconData = activeBeacons.get(key);

                            if (beaconData?.location) {
                                overworld.spawnParticle(`cbcl_rm:beacon_disappear_1_${beaconType}`, beaconData.location);
                                overworld.spawnParticle(`cbcl_rm:beacon_disappear_2_${beaconType}`, beaconData.location);
                            }

                            activeBeacons.delete(key);
                        }
                    }
                }
            } catch (e) {}
        }
    }
    else if (!loggedOutPlayers.includes(player.id) && player.getDynamicProperty("cbcl_rm:dead")) {
        loggedOutPlayers.push(player.id);

        const overworld = world.getDimension("overworld");
        const beaconType = (world.getDynamicProperty("beacon_type") ?? "Red").toLowerCase();

        for (const key of activeBeacons.keys()) {
            if (key.startsWith(player.id + "_")) {
                const beaconData = activeBeacons.get(key);

                if (beaconData?.location) {
                    overworld.spawnParticle(`cbcl_rm:beacon_disappear_1_${beaconType}`, beaconData.location);
                    overworld.spawnParticle(`cbcl_rm:beacon_disappear_2_${beaconType}`, beaconData.location);
                }

                activeBeacons.delete(key);
            }
        }
    }

    world.setDynamicProperty("logged_out_players", JSON.stringify(loggedOutPlayers));
});
function waitForPlayerLoaded(player, callback) {
    const interval = system.runInterval(() => {
        if (player.getComponent("health")) {
            system.clearRun(interval);
            callback();
        }
    }, 1);
}

world.afterEvents.playerSpawn.subscribe(event => {
    const player = event.player;
    waitForPlayerLoaded(player, () => {
        let loggedOutPlayers = JSON.parse(world.getDynamicProperty("logged_out_players") || "[]");

        if (loggedOutPlayers.includes(player.id) && player.getDynamicProperty("cbcl_rm:dead")) {
            player.addTag("cbcl_rm_logout_death");
            triggeredPlayers.add(player.id);
            revivingPlayers.add(player.id);
            world.sendMessage(`§c${player.name} logged out and their stuff was dropped!`);

            handleReviveChoice2(player);
        }
    });
});

function isPlayerLoggedOut(player) {
    const loggedOutPlayers = JSON.parse(world.getDynamicProperty("logged_out_players") || "[]");
    return loggedOutPlayers.includes(player.id);
}
function forceDeath(player) {
    try {
        player.runCommand("gamerule doimmediaterespawn false")
        player.runCommand("clearspawnpoint @s");
        system.runTimeout(() => {
            player.runCommand("kill @s");
        }, 1);
        system.runTimeout(() => {
            player.runCommand("gamerule keepinventory true");
        }, 100);
    } catch (e) { }
}