import { world, system, EntityDamageCause, Player, ItemStack, EquipmentSlot, BlockPermutation, GameMode } from "@minecraft/server";
import { ActionFormData, ModalFormData, MessageFormData } from "@minecraft/server-ui";

// --- Constants & Config ---
const BEDROCK_ROOM_LOC = { x: 0, y: 100, z: 0 }; // Waiting room coordinates
const PENALTY_SECONDS = 180; // Death penalty (seconds)
const ITEM_FLINT = "minecraft:flint_and_steel";
const ITEM_LOG = "minecraft:oak_log";
const ITEM_BREAD = "minecraft:bread";
const ITEM_START = "minecraft:clock"; // Start item
const ITEM_DEBUG = "minecraft:book";  // Debug item

// Game Modes
const MODE = {
    CHOICE: 0,
    RANDOM: 1,
    SPEEDRUN: 2
};

// Perks Definition
const PERKS = [
    // --- Tier 1: Basic / Utility ---
    {
        id: "piglin_friend",
        name: "§6Piglin Friend",
        desc: "Respawn with full Golden Armor",
        tier: 1,
    },
    {
        id: "hasty_miner",
        name: "§eHasty Miner",
        desc: "Permanent Haste II",
        tier: 1,
        onTick: (player) => player.addEffect("haste", 40, { amplifier: 1, showParticles: false })
    },
    {
        id: "night_owl",
        name: "§9Night Owl",
        desc: "Permanent Night Vision",
        tier: 1,
        onTick: (player) => player.addEffect("night_vision", 400, { showParticles: false })
    },
    {
        id: "chef_choice",
        name: "§6Chef's Choice",
        desc: "Respawn with 16 Golden Carrots",
        tier: 1,
    },

    // --- Tier 2: Survival / Exploration ---
    {
        id: "fire_proof",
        name: "§cFire Proof",
        desc: "Permanent Fire Resistance",
        tier: 2,
        onTick: (player) => player.addEffect("fire_resistance", 40, { showParticles: false })
    },
    {
        id: "no_fall",
        name: "§bNo Fall",
        desc: "Permanent Slow Falling (No Fall Damage)",
        tier: 2,
        onTick: (player) => player.addEffect("slow_falling", 40, { showParticles: false })
    },
    {
        id: "super_jump",
        name: "§aSuper Jump",
        desc: "Permanent Jump Boost II",
        tier: 2,
        onTick: (player) => player.addEffect("jump_boost", 40, { amplifier: 1, showParticles: false })
    },
    {
        id: "water_kid",
        name: "§3Water Kid",
        desc: "Permanent Water Breathing & Conduit Power",
        tier: 2,
        onTick: (player) => {
            player.addEffect("water_breathing", 40, { showParticles: false });
            player.addEffect("conduit_power", 40, { showParticles: false });
        }
    },

    // --- Tier 3: Speed / Combat ---
    {
        id: "speedster",
        name: "§bSpeedster",
        desc: "Permanent Speed V",
        tier: 3,
        onTick: (player) => player.addEffect("speed", 40, { amplifier: 4, showParticles: false })
    },
    {
        id: "hulk_smash",
        name: "§4Hulk Smash",
        desc: "Permanent Strength II",
        tier: 3,
        onTick: (player) => player.addEffect("strength", 40, { amplifier: 1, showParticles: false })
    },
    {
        id: "iron_stomach",
        name: "§6Iron Stomach",
        desc: "Permanent Saturation (No Hunger)",
        tier: 3,
        onTick: (player) => player.addEffect("saturation", 40, { amplifier: 0, showParticles: false })
    },
    {
        id: "wolverine",
        name: "§dRegeneration",
        desc: "Permanent Regeneration",
        tier: 3,
        onTick: (player) => player.addEffect("regeneration", 40, { amplifier: 0, showParticles: false })
    },
    
    // --- Tier 4: RTA Special ---
    {
        id: "ender_gift",
        name: "§5Enderman's Gift",
        desc: "Respawn with 4 Ender Pearls",
        tier: 4,
    },
    {
        id: "blaze_gift",
        name: "§6Blaze's Gift",
        desc: "Respawn with 2 Blaze Rods",
        tier: 4,
    },
    {
        id: "vampire",
        name: "§4Vampire",
        desc: "Heal HP upon killing enemies",
        tier: 4,
    },
    {
        id: "explosive_punch",
        name: "§cExplosive Punch",
        desc: "Attacks cause explosions",
        tier: 4,
    },

    // --- Tier 99: Random Only / Debuffs ---
    {
        id: "walking_bomb",
        name: "§c§kWalking Bomb",
        desc: "Explode every 3s (No terrain damage)",
        tier: 99,
        isRandomOnly: true,
        isTemporary: true,
        onTick: (player) => {
            if (system.currentTick % 60 === 0) {
                player.dimension.createExplosion(player.location, 2, { breaksBlocks: false, source: player });
            }
        }
    },
    {
        id: "rocket_man",
        name: "§c§kRocket Man",
        desc: "Permanent Levitation (Float away)",
        tier: 99,
        isRandomOnly: true,
        isTemporary: true,
        onTick: (player) => player.addEffect("levitation", 40, { amplifier: 0, showParticles: false })
    },
    {
        id: "snail_curse",
        name: "§c§kSnail Curse",
        desc: "Permanent Slowness VI (Can barely move)",
        tier: 99,
        isRandomOnly: true,
        isTemporary: true,
        onTick: (player) => player.addEffect("slowness", 40, { amplifier: 5, showParticles: false })
    },
    {
        id: "blind_bat",
        name: "§c§kBlind Bat",
        desc: "Permanent Blindness",
        tier: 99,
        isRandomOnly: true,
        isTemporary: true,
        onTick: (player) => player.addEffect("blindness", 40, { showParticles: false })
    }
];

// --- Global Variables ---
let gameState = {
    isRunning: false,
    startTime: 0,
    penaltyTime: 0, // seconds
    mode: MODE.CHOICE
};
let isSetupDone = false; 

// Player Data Map
const playerData = new Map(); 
const lookingUpMap = new Map(); // Track looking up state

function getPlayerData(player) {
    if (!playerData.has(player.name)) {
        playerData.set(player.name, { perks: [], isDead: false });
    }
    return playerData.get(player.name);
}

// Helper: Safe Run Timeout
function safeRunTimeout(callback, ticks) {
    if (typeof system.runTimeout === 'function') {
        system.runTimeout(callback, ticks);
    } else {
        // Fallback using runInterval for older APIs
        let counter = 0;
        const interval = system.runInterval(() => {
            counter++;
            if (counter >= ticks) {
                system.clearRun(interval);
                callback();
            }
        }, 1);
    }
}

// Helper: Get Dimension Safe (Tries both 'overworld' and 'minecraft:overworld')
function getOverworldDimension() {
    try {
        const dim = world.getDimension("overworld");
        if (dim) return dim;
    } catch {}
    try {
        const dim = world.getDimension("minecraft:overworld");
        if (dim) return dim;
    } catch {}
    return null;
}

// Helper: Run Command Safely (The Ultimate Fallback Machine)
function runCommand(player, command) {
    console.warn(`[Debug] runCommand request: ${command} (Target: ${player ? player.name : 'Unknown'})`);
    
    const dim = player?.dimension || getOverworldDimension();

    // 1. Try Dimension Async (Preferred - Server Authority)
    if (dim && typeof dim.runCommandAsync === 'function') {
        dim.runCommandAsync(command)
            .then(() => console.warn(`[Debug] Success (DimAsync): ${command}`))
            .catch(e => {
                console.warn(`[Debug] Fail (DimAsync): ${e}. Trying fallback...`);
                runCommandFallback(player, dim, command);
            });
        return;
    }

    // 2. Try Dimension Sync (Legacy Server Authority)
    if (dim && typeof dim.runCommand === 'function') {
        try {
            dim.runCommand(command);
            console.warn(`[Debug] Success (DimSync): ${command}`);
            return;
        } catch (e) {
            console.warn(`[Debug] Fail (DimSync): ${e}`);
        }
    }

    runCommandFallback(player, dim, command);
}

function runCommandFallback(player, dim, command) {
    // 3. Try Player Async (Player Permission)
    if (player && typeof player.runCommandAsync === 'function') {
        player.runCommandAsync(command)
            .then(() => console.warn(`[Debug] Success (PlrAsync): ${command}`))
            .catch(e => console.warn(`[Debug] Fail (PlrAsync): ${e}`));
        return;
    }

    // 4. Try Player Sync (Legacy Player Permission)
    if (player && typeof player.runCommand === 'function') {
        try {
            player.runCommand(command);
            console.warn(`[Debug] Success (PlrSync): ${command}`);
            return;
        } catch (e) {
            console.warn(`[Debug] Fail (PlrSync): ${e}`);
        }
    }

    console.warn(`[Debug] Critical: No command execution method found for: ${command}`);
}

// Helper: Teleport Spectator to Random Player
function teleportToRandomPlayer(spectator) {
    console.warn(`[Debug] teleportToRandomPlayer called for ${spectator.name}`);
    try {
        const players = world.getAllPlayers();
        // Filter out self and dead players (or non-challengers if possible)
        const targets = players.filter(p => p.id !== spectator.id && p.hasTag("challenger"));
        console.warn(`[Debug] Valid targets: ${targets.length}`);

        if (targets.length > 0) {
            const target = targets[Math.floor(Math.random() * targets.length)];
            spectator.teleport(target.location, { dimension: target.dimension });
            spectator.sendMessage(`§a[System] Teleported to ${target.name}.`);
        } else {
            spectator.sendMessage("§c[System] No valid players (Challengers) found to teleport to.");
        }
    } catch (e) {
        console.warn(`[Debug] Error in teleportToRandomPlayer: ${e}`);
    }
}

// Helper: Ensure Spectator Mode (Retry loop)
function ensureSpectatorMode(player) {
    console.warn(`[Debug] ensureSpectatorMode called for ${player.name}`); 
    let attempts = 0;
    const maxAttempts = 15;
    
    const attemptLoop = () => {
        if (!player) return;
        try { if (player.isValid && !player.isValid()) return; } catch { return; }

        attempts++;
        console.warn(`[Debug] Spectator Loop ${attempts}/${maxAttempts} for ${player.name}`);
        
        // Use Name explicitly for gamemode command
        runCommand(player, `execute as @a[name="${player.name}"] run gamemode spectator @s`);

        // Teleport attempts (Force update position)
        if (attempts === 5 || attempts === 10 || attempts === maxAttempts) {
             console.warn(`[Debug] Attempting scheduled teleport in loop ${attempts}`);
             teleportToRandomPlayer(player);
        }

        if (attempts < maxAttempts) {
            safeRunTimeout(attemptLoop, 20); 
        } else {
            console.warn(`[Debug] Max attempts reached for ${player.name}. Loop finished.`);
        }
    };
    
    safeRunTimeout(attemptLoop, 20);
}

// --- Initialization & Item Distribution ---

// Give Lobby Items (Host Only Clock)
function giveLobbyItems(player) {
    try {
        const inventory = player.getComponent("inventory").container;
        let hasStartItem = false;
        let startItemSlot = -1;

        for (let i = 0; i < inventory.size; i++) {
            const item = inventory.getItem(i);
            if (!item) continue;
            
            if (item.typeId === ITEM_START) {
                hasStartItem = true;
                startItemSlot = i;
            }
            
            // Remove game items in lobby
            if (item.typeId === ITEM_FLINT || item.typeId === ITEM_LOG || item.typeId === ITEM_BREAD) {
                inventory.setItem(i, undefined);
            }
        }

        const allPlayers = world.getAllPlayers();
        let hostExists = allPlayers.some(p => p.hasTag("host"));

        if (!hostExists) {
            player.addTag("host");
            player.sendMessage("§eYou are now the Host player.");
        }

        if (player.hasTag("host")) {
            if (!hasStartItem) {
                const clock = new ItemStack(ITEM_START, 1);
                clock.nameTag = "§aGame Start Switch";
                inventory.addItem(clock);
                player.sendMessage("§eUse the 'Game Start Switch (Clock)' to start the game.");
            }
        } else {
            if (hasStartItem && startItemSlot !== -1) {
                inventory.setItem(startItemSlot, undefined);
                player.sendMessage("§7Start item removed as you are not the Host. Please wait.");
            }
        }

    } catch (e) {
        console.warn("Failed giveLobbyItems", e);
    }
}

// Give Game Items (Mode Dependent)
function giveGameItems(player) {
    try {
        const inventory = player.getComponent("inventory").container;
        const equipment = player.getComponent("equippable");
        const data = getPlayerData(player);
        const perks = data.perks;

        // Remove clock
        for (let i = 0; i < inventory.size; i++) {
            const item = inventory.getItem(i);
            if (item && item.typeId === ITEM_START) {
                inventory.setItem(i, undefined);
            }
        }

        // --- Basic Items ---
        let hasFlint = false;
        for(let i=0; i<inventory.size; i++) {
            if(inventory.getItem(i)?.typeId === ITEM_FLINT) hasFlint = true;
        }
        if (!hasFlint) {
            inventory.addItem(new ItemStack(ITEM_FLINT, 1));
        }

        // 2. Logs & Bread (Except Speedrun)
        if (gameState.mode !== MODE.SPEEDRUN) {
            let hasLog = false;
            let hasBread = false;
            for(let i=0; i<inventory.size; i++) {
                const item = inventory.getItem(i);
                if(!item) continue;
                if(item.typeId === ITEM_LOG) hasLog = true;
                if(item.typeId === ITEM_BREAD) hasBread = true;
            }
            if (!hasLog) inventory.addItem(new ItemStack(ITEM_LOG, 5));
            if (!hasBread) inventory.addItem(new ItemStack(ITEM_BREAD, 16));
        }

        // --- Perk Items ---
        if (perks.includes("piglin_friend") && equipment) {
            const head = equipment.getEquipment(EquipmentSlot.Head);
            if (!head) equipment.setEquipment(EquipmentSlot.Head, new ItemStack("minecraft:golden_helmet"));
            const chest = equipment.getEquipment(EquipmentSlot.Chest);
            if (!chest) equipment.setEquipment(EquipmentSlot.Chest, new ItemStack("minecraft:golden_chestplate"));
            const legs = equipment.getEquipment(EquipmentSlot.Legs);
            if (!legs) equipment.setEquipment(EquipmentSlot.Legs, new ItemStack("minecraft:golden_leggings"));
            const feet = equipment.getEquipment(EquipmentSlot.Feet);
            if (!feet) equipment.setEquipment(EquipmentSlot.Feet, new ItemStack("minecraft:golden_boots"));
        }
        
        let hasGoldenCarrot = false;
        let hasEnderPearl = false;
        let hasBlazeRod = false;
        for(let i=0; i<inventory.size; i++) {
            const item = inventory.getItem(i);
            if(!item) continue;
            if (item.typeId === "minecraft:golden_carrot") hasGoldenCarrot = true;
            if (item.typeId === "minecraft:ender_pearl") hasEnderPearl = true;
            if (item.typeId === "minecraft:blaze_rod") hasBlazeRod = true;
        }

        if (perks.includes("chef_choice") && !hasGoldenCarrot) {
            inventory.addItem(new ItemStack("minecraft:golden_carrot", 16));
        }
        if (perks.includes("ender_gift") && !hasEnderPearl) {
            inventory.addItem(new ItemStack("minecraft:ender_pearl", 4));
        }
        if (perks.includes("blaze_gift") && !hasBlazeRod) {
            inventory.addItem(new ItemStack("minecraft:blaze_rod", 2));
        }

    } catch(e) {
        console.warn("Failed giveGameItems", e);
    }
}

// --- Event: Player Spawn ---
world.afterEvents.playerSpawn.subscribe((event) => {
    const { player } = event;
    console.warn(`[Debug] Player Spawned: ${player.name}`);

    // Small delay to ensure player object is ready
    safeRunTimeout(() => {
        // 1. Game Running
        if (gameState.isRunning) {
            console.warn(`[Debug] Game running check for ${player.name}`);
            
            // If has tag, survival (respawned player)
            if (player.hasTag("challenger")) {
                console.warn(`[Debug] Player is challenger.`);
                runCommand(player, `execute as @a[name="${player.name}"] run gamemode survival @s`);
                return;
            }

            // No tag = Late joiner -> Spectator
            console.warn(`[Debug] Player is late joiner.`);
            try {
                // Immediate attempt
                runCommand(player, `execute as @a[name="${player.name}"] run gamemode spectator @s`);
                player.sendMessage("§c§lGame is currently in progress. Switching to Spectator Mode...");
                player.sendMessage("§7Look straight UP (at the sky) to teleport to a random player.");
                
                ensureSpectatorMode(player);
            } catch (e) { console.warn(`[Debug] Error in spawn handler: ${e}`); }
            return;
        }

        // 2. Before Game (Lobby)
        if (isSetupDone) {
            try {
                const tpLoc = { ...BEDROCK_ROOM_LOC, y: BEDROCK_ROOM_LOC.y + 1 };
                player.teleport(tpLoc);
                runCommand(player, `execute as @a[name="${player.name}"] run gamemode survival @s`);
                giveLobbyItems(player); 
            } catch (e) { console.warn(e); }
        }
    }, 5); 
});

// --- Event: Player Leave (Host Migration) ---
world.afterEvents.playerLeave.subscribe((event) => {
    safeRunTimeout(() => {
        const allPlayers = world.getAllPlayers();
        if (allPlayers.length === 0) return;

        const hostExists = allPlayers.some(p => p.hasTag("host"));
        if (!hostExists) {
            const newHost = allPlayers[0];
            newHost.addTag("host");
            newHost.sendMessage("§eYou have become the new Host as the previous one left.");
            if (!gameState.isRunning) {
                giveLobbyItems(newHost);
            }
        }
    }, 20);
});


// --- Event: Item Use ---
world.afterEvents.itemUse.subscribe((event) => {
    const { source: player, itemStack } = event;
    
    // Host Menu (Clock)
    if (itemStack.typeId === ITEM_START) {
        showHostMenu(player);
    }
});

// --- Host Menu ---
async function showHostMenu(player) {
    if (!player.hasTag("host")) {
        player.sendMessage("§cOnly the Host can use this menu.");
        return;
    }

    const form = new ActionFormData()
        .title("Nether Speedrun - Host Menu")
        .body("Control Panel")
        .button("Start Game", "textures/items/diamond_sword")
        .button("Reset Game & Setup", "textures/ui/refresh");

    try {
        const response = await form.show(player);
        if (response.canceled) return;

        if (response.selection === 0) {
            if (gameState.isRunning) {
                player.sendMessage("§cGame is already running.");
            } else {
                showModeSelection(player);
            }
        } else if (response.selection === 1) {
            // Reset
            gameState = { isRunning: false, startTime: 0, penaltyTime: 0, mode: MODE.CHOICE };
            playerData.clear();
            runCommand(player, "gamerule falldamage true");
            
            (async () => {
                await setupBedrockRoom(player);
                for(const p of world.getAllPlayers()) {
                        p.removeTag("challenger");
                        runCommand(p, `execute as @a[name="${p.name}"] run gamemode survival @s`);
                        const tpLoc = { ...BEDROCK_ROOM_LOC, y: BEDROCK_ROOM_LOC.y + 1 };
                        p.teleport(tpLoc);
                        giveLobbyItems(p);
                        p.sendMessage("§eGame has been reset by Host.");
                }
            })();
        }
    } catch (e) {}
}

// Mode Selection (Sub Menu)
async function showModeSelection(player) {
    const form = new ActionFormData()
        .title("Nether Speedrun - Mode Select")
        .body("Start Game? Select a mode.\n*Late joiners will become spectators once started.")
        .button("Choice Mode\nSelect a perk upon death", "textures/items/diamond")
        .button("Random Mode\nRandom perks (Includes debuffs)", "textures/items/gold_nugget")
        .button("Speedrun Mode\nNo Perks (Pure RTA)", "textures/items/diamond_boots");

    try {
        const response = await form.show(player);
        if (response.canceled) return;

        // Game Start
        gameState.mode = response.selection;
        gameState.isRunning = true;
        gameState.startTime = Date.now();
        gameState.penaltyTime = 0;
        
        world.sendMessage(`§l§aGame Start! Mode: ${["Choice", "Random", "Speedrun"][gameState.mode]}`);
        world.sendMessage("Enter the Nether Portal and survive the return from The End!");
        
        for (const p of world.getAllPlayers()) {
            p.addTag("challenger");
            giveGameItems(p);
        }

    } catch (e) {
        console.warn("Error showing mode selection:", e);
    }
}

// Perk Selection UI (Death)
async function showPerkSelection(player) {
    const data = getPlayerData(player);
    const availablePerks = PERKS.filter(p => !data.perks.includes(p.id) && !p.isRandomOnly);
    
    if (availablePerks.length === 0) {
        player.sendMessage("§eNo more perks available!");
        return;
    }
    const choices = availablePerks.sort(() => 0.5 - Math.random()).slice(0, 3);

    const form = new ActionFormData()
        .title("You Died! Choose a Perk")
        .body(`Death Penalty: +${PENALTY_SECONDS}s\nChoose a perk to come back stronger.`);

    choices.forEach(perk => {
        // Show Name AND Description
        form.button(`${perk.name}\n${perk.desc}`);
    });

    try {
        const response = await form.show(player);
        if (response.canceled) {
            const randomPerk = choices[0];
            addPerk(player, randomPerk.id);
            return;
        }
        const selectedPerk = choices[response.selection];
        addPerk(player, selectedPerk.id);
    } catch (e) {
        console.warn("Error showing perk selection:", e);
    }
}

// Add Perk Function (Fixed Definition)
function addPerk(player, perkId) {
    const data = getPlayerData(player);
    if (!data.perks.includes(perkId)) {
        data.perks.push(perkId);
        const perk = PERKS.find(p => p.id === perkId);
        if(perk) {
            player.sendMessage(`§l§aPerk Acquired: ${perk.name}`);
            player.sendMessage(`§7Effect: ${perk.desc}`);
            if (perk.onAcquire) {
                try { perk.onAcquire(player); } catch (e) {}
            }
        }
    }
    giveGameItems(player);
}

// --- Setup Bedrock Room ---
async function setupBedrockRoom(player = null) {
    const dim = getOverworldDimension();
    if (!dim) return;

    try {
        runCommand(player, "tickingarea remove bedrock_room");
        runCommand(player, `tickingarea add circle ${BEDROCK_ROOM_LOC.x} ${BEDROCK_ROOM_LOC.y} ${BEDROCK_ROOM_LOC.z} 2 bedrock_room`);
        
        await new Promise(resolve => safeRunTimeout(resolve, 20));
    } catch (e) {}

    for (let i = 0; i < 2; i++) {
        try {
            for (let x = -3; x <= 3; x++) {
                for (let y = 0; y <= 6; y++) {
                    for (let z = -3; z <= 3; z++) {
                        const loc = { x: BEDROCK_ROOM_LOC.x + x, y: BEDROCK_ROOM_LOC.y + y, z: BEDROCK_ROOM_LOC.z + z };
                        try {
                            const block = dim.getBlock(loc);
                            if (block) {
                                if (x === -3 || x === 3 || y === 0 || y === 6 || z === -3) {
                                    if (x === 0 && y === 6 && z === 0) {
                                         block.setPermutation(BlockPermutation.resolve("minecraft:bedrock"));
                                    } else {
                                         block.setPermutation(BlockPermutation.resolve("minecraft:bedrock"));
                                    }
                                } else if (z === 3) {
                                    block.setPermutation(BlockPermutation.resolve("minecraft:bedrock")); 
                                } else {
                                     if (x === 0 && y === 5 && z === 0) {
                                        block.setPermutation(BlockPermutation.resolve("minecraft:light_block", { "block_light_level": 15 }));
                                     } else {
                                        block.setPermutation(BlockPermutation.resolve("minecraft:air"));
                                     }
                                }
                            }
                        } catch (err) {}
                    }
                }
            }
            const obsidianLocs = [];
            for (let x = -2; x <= 2; x++) {
                obsidianLocs.push({x: x, y: 1, z: 3});
                obsidianLocs.push({x: x, y: 6, z: 3});
            }
            for (let y = 2; y <= 5; y++) {
                obsidianLocs.push({x: -2, y: y, z: 3});
                obsidianLocs.push({x: 2, y: y, z: 3});
            }
            for (const pos of obsidianLocs) {
                const loc = { x: BEDROCK_ROOM_LOC.x + pos.x, y: BEDROCK_ROOM_LOC.y + pos.y, z: BEDROCK_ROOM_LOC.z + pos.z };
                dim.getBlock(loc)?.setPermutation(BlockPermutation.resolve("minecraft:obsidian"));
            }
            for (let x = -1; x <= 1; x++) {
                for (let y = 2; y <= 5; y++) {
                    const loc = { x: BEDROCK_ROOM_LOC.x + x, y: BEDROCK_ROOM_LOC.y + y, z: BEDROCK_ROOM_LOC.z + 3 };
                    dim.getBlock(loc)?.setPermutation(BlockPermutation.resolve("minecraft:air"));
                }
            }
            for (let x = -3; x <= 3; x++) {
                for (let y = 0; y <= 6; y++) {
                    for (let zOffset = 1; zOffset <= 3; zOffset++) {
                        const loc = { x: BEDROCK_ROOM_LOC.x + x, y: BEDROCK_ROOM_LOC.y + y, z: BEDROCK_ROOM_LOC.z + 3 + zOffset };
                        dim.getBlock(loc)?.setPermutation(BlockPermutation.resolve("minecraft:bedrock"));
                    }
                }
            }
        } catch (e) {}
        
        await new Promise(resolve => safeRunTimeout(resolve, 10));
    }
}

// --- Main Loop ---
system.runInterval(() => {
    // Auto Setup
    if (!isSetupDone) {
        const players = world.getAllPlayers();
        if (players.length > 0) {
            isSetupDone = true;
            (async () => {
                await setupBedrockRoom(players[0]);
                for (const p of players) {
                    try {
                        const tpLoc = { ...BEDROCK_ROOM_LOC, y: BEDROCK_ROOM_LOC.y + 1 };
                        p.teleport(tpLoc);
                        p.sendMessage("§aWelcome to Nether Speedrun!");
                        giveLobbyItems(p); 
                    } catch (e) {}
                }
            })();
        }
    }

    if (gameState.isRunning) {
        const now = Date.now();
        const elapsedSeconds = Math.floor((now - gameState.startTime) / 1000) + gameState.penaltyTime;
        const h = Math.floor(elapsedSeconds / 3600);
        const m = Math.floor((elapsedSeconds % 3600) / 60);
        const s = elapsedSeconds % 60;
        const timeStr = `${h > 0 ? h + ':' : ''}${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;

        for (const player of world.getAllPlayers()) {
            // Check Spectator Teleport (Look Up)
            if (!player.hasTag("challenger")) {
                const rotation = player.getRotation();
                // -85 is almost straight up
                const isLookingUp = rotation.x < -85;
                
                if (isLookingUp && !lookingUpMap.get(player.id)) {
                    teleportToRandomPlayer(player);
                }
                lookingUpMap.set(player.id, isLookingUp);
            }

            if (player.hasTag("challenger")) {
                const data = getPlayerData(player);
                let currentHp = 20;
                try {
                    const healthComp = player.getComponent("minecraft:health");
                    if (healthComp) currentHp = healthComp.currentValue;
                } catch (e) {}

                // Death
                if (currentHp <= 0 && !data.isDead) {
                    data.isDead = true;
                    gameState.penaltyTime += PENALTY_SECONDS;
                    world.sendMessage(`§c§lDEATH! §rPenalty +${PENALTY_SECONDS}s`);
                    
                    const originalPerkCount = data.perks.length;
                    data.perks = data.perks.filter(perkId => {
                        const perkDef = PERKS.find(p => p.id === perkId);
                        return !perkDef || !perkDef.isTemporary;
                    });
                    if (data.perks.length < originalPerkCount) {
                        player.sendMessage("§eChaos skills cleansed.");
                    }
                }

                // Respawn
                if (currentHp > 0 && data.isDead) {
                    data.isDead = false;
                    try { 
                        const tpLoc = { ...BEDROCK_ROOM_LOC, y: BEDROCK_ROOM_LOC.y + 1 };
                        player.teleport(tpLoc); 
                    } catch(e){}

                    if (gameState.mode === MODE.CHOICE) {
                        safeRunTimeout(() => { showPerkSelection(player).catch(console.error); }, 20);
                    } else if (gameState.mode === MODE.RANDOM) {
                        const availablePerks = PERKS.filter(p => !data.perks.includes(p.id));
                        const isOnlyDebuffsLeft = availablePerks.every(p => p.isRandomOnly);
                        if (availablePerks.length > 0 && !isOnlyDebuffsLeft) {
                            const randomPerk = availablePerks[Math.floor(Math.random() * availablePerks.length)];
                            addPerk(player, randomPerk.id);
                        } else {
                            player.sendMessage("§eYou have learned all useful perks!");
                        }
                    } else {
                        player.sendMessage("§cSpeedrun Mode: No Pain, No Gain.");
                    }
                    giveGameItems(player);
                }

                try {
                    player.onScreenDisplay.setActionBar(`§l§6Time: ${timeStr} §r(Deaths: ${Math.floor(gameState.penaltyTime / PENALTY_SECONDS)})`);
                } catch(e) {}
                
                data.perks.forEach(perkId => {
                    const perk = PERKS.find(p => p.id === perkId);
                    if (perk && perk.onTick) {
                        try { perk.onTick(player); } catch(e) {}
                    }
                });
            }
        }
    }
}, 1);

// Event Processing
world.afterEvents.playerDimensionChange.subscribe((event) => {
    if (!gameState.isRunning) return;
    const { player, fromDimension, toDimension } = event;

    // ★Added: Ignore if not a challenger (spectator)
    if (!player.hasTag("challenger")) return;

    const data = getPlayerData(player);
    if (data.isDead) return;

    if (fromDimension.id === "minecraft:the_end" && toDimension.id === "minecraft:overworld") {
        finishGame(player);
    }
});

function finishGame(winner) {
    gameState.isRunning = false;
    const now = Date.now();
    const elapsedSeconds = Math.floor((now - gameState.startTime) / 1000) + gameState.penaltyTime;
    const h = Math.floor(elapsedSeconds / 3600);
    const m = Math.floor((elapsedSeconds % 3600) / 60);
    const s = elapsedSeconds % 60;
    const timeStr = `${h > 0 ? h + ':' : ''}${m.toString().padStart(2, '0')}:${s.toString().padStart(2, '0')}`;
    
    const modeName = ["Choice", "Random", "Speedrun"][gameState.mode];
    const deathCount = Math.floor(gameState.penaltyTime / PENALTY_SECONDS);

    world.sendMessage(`§e========================================`);
    world.sendMessage(`§6§l🎉 CONGRATULATIONS! 🎉`);
    world.sendMessage(`§bWinner: §f${winner.name}`);
    world.sendMessage(`§dMode: §f${modeName}`);
    world.sendMessage(`§aTime: §l${timeStr}`);
    world.sendMessage(`§cDeaths: §f${deathCount}`);
    world.sendMessage(`§e========================================`);
    
    for (const p of world.getAllPlayers()) {
        try {
            if (p.onScreenDisplay) {
                p.onScreenDisplay.setTitle(`§6§l=== VICTORY! ===`);
                p.onScreenDisplay.setSubtitle(`§7[${modeName}]§r\n§aTime: ${timeStr} §cDeaths: ${deathCount}`);
            }
            runCommand(p, "playsound random.totem @s");
        } catch(e) { }
    }

    const celebrate = (count) => {
        if (count > 10) return; 
        for (const p of world.getAllPlayers()) {
            try {
                if (p.dimension) {
                    const rx = (Math.random() - 0.5) * 4;
                    const rz = (Math.random() - 0.5) * 4;
                    runCommand(p, `summon minecraft:fireworks_rocket ~${rx.toFixed(1)} ~2 ~${rz.toFixed(1)}`);
                    runCommand(p, "playsound random.levelup @s");
                }
            } catch(e) {}
        }
        safeRunTimeout(() => celebrate(count + 1), 20);
    };
    celebrate(0);
}