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

const particleRange = 20; // Close particles range
const particlesPerSecond = 20; // Amount of close particles
const particleIds = [
    "lv_zo:fog_mist",
    "lv_zo:fog_mist_large",
    "lv_zo:ash_emitter",
]; // Close-range particles
const maxDepthCheck = 8; // Maximum depth check for ground detection

const minDistance = 10; // Minimum distance from the player
const maxDistance = 20; // Maximum distance
const particlesSurroundPerSecond = 20; // Amount of surrounding particles
const particleSurroundIds = ["lv_zo:fog_surround"]; // Surrounding particle effects

let hordeEffectTaskId = null; // Store interval ID for fog & particles
let hordeSoundTaskId = null; // Store interval ID for ambient sound

/**
 * Toggles Horde Night effects & ambient sound on or off
 */
export function toggleHordeEffects(toggle) {
    if (toggle) {
        if (hordeEffectTaskId !== null) {
            // Ensure previous interval is stopped
            system.clearRun(hordeEffectTaskId);
            system.clearRun(hordeSoundTaskId);
            clearAllEffects(true); // Force clear
        }

        // Start new intervals
        hordeEffectTaskId = system.runInterval(applyHordeEffects, 7); // every 7 ticks
        playAmbientSound("lv_zo.horde_night.fade_in");
        hordeSoundTaskId = system.runInterval(playAmbientSound, 750); // every 750 ticks
    } else {
        if (hordeEffectTaskId !== null) {
            playAmbientSound("lv_zo.horde_night.fade_out");

            // Stop intervals
            system.clearRun(hordeEffectTaskId);
            system.clearRun(hordeSoundTaskId);
            hordeEffectTaskId = null;
            hordeSoundTaskId = null;

            // Aggressively remove all effects from players
            for (const player of world.getPlayers()) {
                try {
                    player.runCommandAsync(`fog @s remove lv_zo:horde_night`);
                    player.runCommandAsync(`effect @s clear`);
                } catch (e) {
                    console.warn(`Failed to clear effects for player ${player.name}: ${e}`);
                }

                // Spawn airdrop above each player
                const loc = player.location;
                const x = Math.floor(loc.x);
                const y = 140;
                const z = Math.floor(loc.z);
                player.dimension.spawnEntity("lv_zo:airdrop", { x, y, z });
            }

            clearAllEffects(true); // Force clear globally
        }
    }
}


export function clearAllEffects(force = false) {
    for (const player of world.getPlayers()) {
        try {
            player.runCommandAsync(`effect @s clear`);
            player.removeTag("horde_night_active");

            player.runCommandAsync(`fog @s remove lv_zo:horde_night`);
            player.runCommandAsync(`stopsound @s ambient.soulsand_valley.loop`);
            if (force) {
                player.runCommandAsync(`fog @s remove lv_zo:horde_night`);
            }
        } catch (e) {
            console.warn(`clearAllEffects failed for ${player.name}: ${e}`);
        }
    }
}

/**
 * Applies particle effects and fog to all players
 */
export function applyHordeEffects() {
    const players = world.getPlayers();

    for (const player of players) {
        // Apply fog effect
        player.runCommandAsync(
            `fog @s push lv_zo:horde_night lv_zo:horde_night`,
        );

        // Check VFX toggle
        let vfxEnabled = true;
        try {
            const objective = world.scoreboard.getObjective(
                "lv_zo_global_toggles",
            );
            const participant = objective?.getParticipants().find((p) =>
                p.displayName === "toggle_vfx"
            );
            if (participant) {
                const score = objective.getScore(participant);
                vfxEnabled = score === 1;
            }
        } catch {
            vfxEnabled = true; // fail-safe default
        }

        if (!vfxEnabled) continue;

        const playerPos = player.location;

        // **Spawn close-range particles**
        for (let i = 0; i < particlesPerSecond; i++) {
            const offsetX = (Math.random() * 2 - 1) * particleRange;
            const offsetZ = (Math.random() * 2 - 1) * particleRange;
            const baseX = Math.floor(playerPos.x + offsetX);
            const baseZ = Math.floor(playerPos.z + offsetZ);

            let groundY = findGroundY(player, baseX, baseZ);

            if (groundY !== null) {
                const randomParticle =
                    particleIds[Math.floor(Math.random() * particleIds.length)];
                player.runCommandAsync(
                    `particle ${randomParticle} ${baseX + 0.5} ${groundY + 1} ${baseZ + 0.5
                    }`,
                );
            }
        }

        // **Spawn surrounding-range particles**
        for (let i = 0; i < particlesSurroundPerSecond; i++) {
            let offsetX, offsetZ, baseX, baseZ, distance;
            do {
                offsetX = (Math.random() * 2 - 1) * maxDistance;
                offsetZ = (Math.random() * 2 - 1) * maxDistance;
                distance = Math.sqrt(offsetX * offsetX + offsetZ * offsetZ);
            } while (distance < minDistance);

            baseX = Math.floor(playerPos.x + offsetX);
            baseZ = Math.floor(playerPos.z + offsetZ);

            let groundY = findGroundY(player, baseX, baseZ);

            if (groundY !== null) {
                const randomParticle =
                    particleSurroundIds[
                    Math.floor(Math.random() * particleSurroundIds.length)
                    ];
                player.runCommandAsync(
                    `particle ${randomParticle} ${baseX + 0.5} ${groundY + 1} ${baseZ + 0.5
                    }`,
                );
            }
        }
    }
}

/**
 * Plays ambient sound for all players
 */
function playAmbientSound(sound_name = "ambient.soulsand_valley.loop") {
    for (const player of world.getPlayers()) {
        player.runCommandAsync(`playsound ${sound_name} @s ~~~ 0.6`);
    }
}

/**
 * Finds the ground level at given X and Z coordinates
 */
function findGroundY(player, x, z) {
    for (let yOffset = 1; yOffset >= -maxDepthCheck; yOffset--) {
        const checkPos = {
            x: x,
            y: Math.floor(player.location.y) + yOffset,
            z: z,
        };
        const block = player.dimension.getBlock(checkPos);

        if (
            block && !block.isAir &&
            [
                "lv_zo:corrupted_soil",
                "lv_zo:corrupted_grass",
                "minecraft:mycelium",
                "minecraft:hardened_clay",
                "minecraft:orange_terracotta",
                "minecraft:sand",
                "minecraft:red_sand",
                "minecraft:grass_block",
                "minecraft:dirt",
                "minecraft:stone",
                "minecraft:pale_moss_block",
                "minecraft:moss_block",
                "minecraft:snow_block",
                "minecraft:powder_snow",
                "minecraft:netherrack",
                "minecraft:lava",
                "minecraft:water",
                "minecraft:sand",
                "minecraft:gravel",
                "minecraft:dirt_path",
            ].includes(block.typeId)
        ) {
            return checkPos.y;
        }
    }
    return null;
}
