import { system, world } from "@minecraft/server";
import { toggleHordeEffects } from "./horde_effects.js"; // Import function

const waveInterval = 16; // Seconds between waves
const strongWaveInterval = 8; // Every 8 waves, a stronger wave will spawn
const waveMinZombies = 5; // Minimum zombies per player per wave
const waveMaxZombies = 12; // Maximum zombies per player per wave

let currentWave = 0;
let waveTaskId = null;

/**
 * Weighted spawn tables for normal and strong waves
 */
const NORMAL_ZOMBIE_TABLE = [
    { type: "lv_zo:zomb", weight: 60 },
    { type: "lv_zo:chubby", weight: 60 },
    { type: "lv_zo:small_zomb", weight: 60 },
    { type: "lv_zo:tanky", weight: 10 },
    { type: "lv_zo:slapstick", weight: 22 },
    { type: "lv_zo:slime_shooter", weight: 22 },
    { type: "lv_zo:zombomb", weight: 22 },
];

const STRONG_ZOMBIE_TABLE = [
    { type: "lv_zo:zomb", weight: 60 },
    { type: "lv_zo:chubby", weight: 60 },
    { type: "lv_zo:small_zomb", weight: 60 },
    { type: "lv_zo:tanky", weight: 50 },
    { type: "lv_zo:slapstick", weight: 62 },
    { type: "lv_zo:slime_shooter", weight: 62 },
    { type: "lv_zo:zombomb", weight: 62 },
];

/**
 * Starts Horde Night by notifying players and starting wave spawning.
 */
export function startHordeNight() {
    world.sendMessage("§8[§2ZOMBIFIED§8]§r The §c§lHorde Night§r has started!");

    for (const player of world.getPlayers()) {
        player.addTag("horde_night_active");
        player.runCommandAsync(
            "playsound lv_zo.horde_night.announcement @s ~~~ 0.6",
        );
        toggleHordeEffects(true);
    }

    // Resume wave spawning if it was interrupted
    if (waveTaskId === null) {
        waveTaskId = system.runInterval(spawnWave, waveInterval * 20); // Convert seconds to ticks
    }
}

/**
 * Ends Horde Night, stops waves, and removes player tags.
 */
export function endHordeNight() {
    world.sendMessage("§8[§2ZOMBIFIED§8]§r Horde night is over!");

    for (const player of world.getPlayers()) {
        player.removeTag("horde_night_active");
    }

    toggleHordeEffects(false);

    // Stop wave spawning
    if (waveTaskId !== null) {
        system.clearRun(waveTaskId);
        waveTaskId = null;
    }
    currentWave = 0; // Reset waves after night ends
}

/**
 * Spawns a wave of zombies using the weighted table.
 */
function spawnWave() {
    currentWave++;
    //world.sendMessage(`§8[§2ZOMBIFIED§8]§r Wave ${currentWave} has begun!`);

    const zombieTable = (currentWave % strongWaveInterval === 0)
        ? STRONG_ZOMBIE_TABLE
        : NORMAL_ZOMBIE_TABLE;

    for (const player of world.getPlayers()) {
        // Determine how many zombies to spawn for this player
        const zombiesToSpawn = getZombiesPerWave();
        spawnZombiesNearPlayer(player, zombieTable, zombiesToSpawn);
    }
}

/**
 * Determines the number of zombies to spawn per wave.
 * @returns {number} - The number of zombies to spawn
 */
function getZombiesPerWave() {
    const waveFactor = Math.floor(currentWave / strongWaveInterval); // Increase zombie count as waves progress
    const minZombies = waveMinZombies + waveFactor;
    const maxZombies = waveMaxZombies + waveFactor;

    return Math.floor(Math.random() * (maxZombies - minZombies + 1)) +
        minZombies;
}

/**
 * Spawns a set number of zombies around a player based on a weighted zombie table.
 */
function spawnZombiesNearPlayer(player, zombieTable, count) {
    let position = player.location;
    const minSpawnDistance = 12; // Minimum distance from player
    const maxSpawnDistance = 22; // Maximum spread distance

    for (let i = 0; i < count; i++) {
        const angle = Math.random() * Math.PI * 2; // Random angle (0 to 360 degrees)
        const distance = Math.random() * (maxSpawnDistance - minSpawnDistance) +
            minSpawnDistance;

        let spawnX = position.x + Math.cos(angle) * distance;
        let spawnZ = position.z + Math.sin(angle) * distance;
        let spawnY = position.y; // Use player's Y level as a base

        const selectedZombie = getWeightedRandom(zombieTable);
        let spawnedZombie = world.getDimension("overworld").spawnEntity(
            selectedZombie,
            { x: spawnX, y: spawnY, z: spawnZ },
        );
        spawnedZombie.triggerEvent("lv_zo:horde_night");
        spawnedZombie.addEffect("speed", 1000, {
            amplifier: 0,
            showParticles: true,
        });
    }
}

/**
 * Selects a zombie type based on weighted probabilities.
 */
function getWeightedRandom(weightedTable) {
    let totalWeight = weightedTable.reduce(
        (sum, entry) => sum + entry.weight,
        0,
    );
    let randomNum = Math.random() * totalWeight;
    let cumulativeWeight = 0;

    for (let entry of weightedTable) {
        cumulativeWeight += entry.weight;
        if (randomNum < cumulativeWeight) {
            return entry.type;
        }
    }

    return weightedTable[0].type; // Default return (failsafe)
}
