import { world, system, MolangVariableMap } from "@minecraft/server";
import { isBlockLoaded } from "../util/block";
import { Vector } from "../util/vector";
import { settingEnabled } from "../settings";

// Variables
const waterSplashesDelayTicks = 2;
const splashCooldown = new Map();
const cooldownDuration = 20;

// Get the highest air block
function getHighestAirBlock(dimension, location, maxHeight = 320) {
    let highestY = -1;
    for (let y = maxHeight; y >= 0; y--) {
        const block = dimension.getBlock({ x: location.x, y, z: location.z });
        // If cannot get block, then skip
        if (!block || !block.isValid) continue;

        if (block.typeId === "minecraft:air") {
            highestY = y;
        } else if (highestY >= 0) {
            // Stop checking when we hit a non-air block after finding the highest air block
            break;
        }
    }
    if (highestY < 0) return null;
    return { x: location.x, y: highestY, z: location.z };
}

// Run main loop
system.runInterval(function() {
    // Return if not enabled
    if (!settingEnabled("splashes")) return;

    // Only work in overworld
    const dimension = world.getDimension("overworld");

    // Grab all entities in world
    const entities = dimension.getEntities();

    // If no entities, return
    if (entities.length === 0) return;

    // Get current tick
    const currentTick = system.currentTick;

    // Check every entity
    entities.forEach(entity => {
        // Get velocity
        const velocity = entity.getVelocity();

        // If velocity is high enough and entity is in water
        if (velocity.y < -0.25 && entity.isInWater) {
            // Grab entity id
            const entityId = entity.id;
            // Check if entity is in cooldown
            const lastSplashTime = splashCooldown.get(entityId) || 0;
            // Skip if cooldown not finished
            if (currentTick - lastSplashTime < cooldownDuration) return;

            // Adjust vertical position of splash effect
            let location = entity.location;
            location.y -= Math.max(velocity.y, -2);

            location = getHighestAirBlock(entity.dimension, location);
            if (!location) return;

            // Schedule splash effect with timeout
            system.runTimeout(() => {
                if (!entity.isValid() || !isBlockLoaded(location, entity.dimension)) return;

                // Determine splash size
                const size = 2;

                // Determine splash height based on velocity
                const height = velocity.y < -1.2 ? "tall" : velocity.y < -0.6 ? "mid" : "low";

                // Set up particle effect variables
                const variables = new MolangVariableMap();
                variables.setFloat("speed", -velocity.y);
                variables.setFloat("radius", size === 1 ? 0.25 : size === 2 ? 0.5 : 1);

                // Particle configuration
                const particleConfig = [
                    { type: "squaredreams_realism:water_splash", variables },
                    { type: "squaredreams_realism:water_splash_ripples", variables },
                    { type: "squaredreams_realism:water_splash_ripple_big", variables },
                    { type: `squaredreams_realism:water_splash_${height}`, variables }
                ];

                // Spawn particles
                particleConfig.forEach(({ type, variables }) => {
                    entity.dimension.spawnParticle(type, location, variables);
                });

                splashCooldown.set(entityId, currentTick);

            }, Math.round(Math.min(velocity.y * -4 - 1, 5)));
        }
    });
}, waterSplashesDelayTicks); // Run the function periodically with defined delay