import { system, world } from "@minecraft/server";
import CustomVector3 from "./calc/vector3";
import { playerBiomeTags } from "./ambienceModule";
import { namespace } from "../config/_config";
var WorldEventStage;
(function (WorldEventStage) {
    WorldEventStage[WorldEventStage["IDLE"] = 0] = "IDLE";
    WorldEventStage[WorldEventStage["START"] = 1] = "START";
    WorldEventStage[WorldEventStage["END"] = 2] = "END";
})(WorldEventStage || (WorldEventStage = {}));
export const playerWorldEvents = new Map();
export class WorldEvent {
    constructor(params) {
        this.id = params.id;
        this.chance = params.chance;
        this.duration = params.duration;
        this.cooldown = params.cooldown;
        this.radius = params.radius;
        this.conditions = params.conditions;
        this.customOnStart = params.customOnStart;
        this.customOnEnd = params.customOnEnd;
        this.effectOptions = params.effectOptions;
        this.dynamicProperty = params.dynamicProperty;
    }
    static register(worldEvent) {
        WorldEvent.worldEvents.push(worldEvent);
    }
    static initialize() {
        WorldEvent.worldEvents.forEach((worldEvent) => {
            system.runInterval(() => {
                const globalRarityProperty = world.getDynamicProperty(`${namespace}:event_frequency`);
                const globalRarity = typeof globalRarityProperty === "number" ? globalRarityProperty : 5;
                // Make globalRarity a stronger multiplier
                const adjustedChance = (worldEvent.chance * (globalRarity / 4)) / 10;
                if (Math.random() < adjustedChance) {
                    const players = world.getPlayers();
                    const eligiblePlayers = players.filter((player) => this.canStartEvent(worldEvent, player));
                    if (eligiblePlayers.length > 0) {
                        const randomIndex = Math.floor(Math.random() * eligiblePlayers.length);
                        const selectedPlayer = eligiblePlayers[randomIndex];
                        this.startEvent(worldEvent, selectedPlayer);
                    }
                }
                WorldEvent.checkEvent(worldEvent);
            }, 20);
        });
    }
    static canStartEvent(worldEvent, player) {
        const currentTime = system.currentTick;
        const eventEndTime = WorldEvent.activeEvents.get(worldEvent.id);
        const cooldownEndTime = WorldEvent.eventCooldowns.get(worldEvent.id);
        const tags = playerBiomeTags.get(player) || [];
        // If dynamicProperty is undefined or true, allow the event to start; if false, do not allow it
        const propertyCheck = worldEvent.dynamicProperty === undefined ||
            world.getDynamicProperty(worldEvent.dynamicProperty) === undefined ||
            world.getDynamicProperty(worldEvent.dynamicProperty) === true;
        const conditionsMet = worldEvent.conditions(player, tags);
        return (propertyCheck && // Check if event is allowed based on dynamicProperty (or undefined)
            conditionsMet && // Check if additional event conditions are met
            (!eventEndTime || currentTime > eventEndTime) && // Check if the event isn't currently active
            (!cooldownEndTime || currentTime > cooldownEndTime) // Check if cooldown has passed
        );
    }
    static removeEvent(worldEvent) {
        const eventLocation = WorldEvent.eventLocations.get(worldEvent);
        if (eventLocation) {
            WorldEvent.eventLocations.delete(worldEvent);
            WorldEvent.activeEvents.delete(worldEvent.id);
            const cooldownEndTime = system.currentTick + worldEvent.cooldown * 20;
            WorldEvent.eventCooldowns.set(worldEvent.id, cooldownEndTime);
            playerWorldEvents.forEach((eventId, playerId) => {
                if (eventId === worldEvent.id) {
                    playerWorldEvents.delete(playerId);
                }
            });
            const intervals = WorldEvent.loopingIntervals.get(worldEvent.id);
            if (intervals) {
                intervals.forEach((interval) => system.clearRun(interval));
                WorldEvent.loopingIntervals.delete(worldEvent.id);
            }
            const players = world.getPlayers();
            players.forEach((player) => {
                const distance = CustomVector3.distance(player.location, eventLocation);
                if (distance < worldEvent.radius) {
                    this.removeEventEffects(worldEvent, player);
                    playerWorldEvents.delete(player.name);
                }
            });
            this.applyEventEndEffects(worldEvent, eventLocation);
            if (worldEvent.customOnEnd) {
                worldEvent.customOnEnd();
            }
        }
    }
    static startEvent(worldEvent, player) {
        const currentTime = system.currentTick;
        const endTime = currentTime + worldEvent.duration * 20;
        WorldEvent.activeEvents.set(worldEvent.id, endTime);
        WorldEvent.eventLocations.set(worldEvent, player.location);
        playerWorldEvents.set(player.name, worldEvent.id);
        WorldEvent.applyVisualEffects(worldEvent, player, WorldEventStage.START);
        if (worldEvent.customOnStart) {
            worldEvent.customOnStart();
        }
        WorldEvent.spawnParticles(worldEvent, player.location);
        system.runTimeout(() => {
            WorldEvent.removeEvent(worldEvent);
        }, worldEvent.duration * 20);
    }
    static checkEvent(worldEvent) {
        if (!WorldEvent.eventLocations.has(worldEvent))
            return;
        const eventLocation = WorldEvent.eventLocations.get(worldEvent);
        if (!eventLocation)
            return;
        const players = world.getPlayers();
        for (const player of players) {
            const playerLocation = player.location;
            const distance = CustomVector3.distance(playerLocation, eventLocation);
            if (distance < worldEvent.radius) {
                this.applyEventEffects(worldEvent, player, eventLocation);
                this.applyVisualEffects(worldEvent, player, WorldEventStage.IDLE);
            }
            if (distance > worldEvent.radius && playerWorldEvents.get(player.name) === worldEvent.id) {
                this.removeEventEffects(worldEvent, player);
                playerWorldEvents.delete(player.name);
            }
        }
    }
    static applyEventEffects(worldEvent, player, location) {
        const { effects } = worldEvent.effectOptions;
        if (effects) {
            const currentTime = system.currentTick;
            const eventEndTime = WorldEvent.activeEvents.get(worldEvent.id);
            if (eventEndTime) {
                const remainingDuration = (eventEndTime - currentTime) * 20;
                effects.forEach((effect) => {
                    player.addEffect(effect.effectType, 40, effect.properties);
                    playerWorldEvents.set(player.name, worldEvent.id);
                });
            }
        }
    }
    static removeEventEffects(worldEvent, player) {
        const { effects } = worldEvent.effectOptions;
        if (effects) {
            effects.forEach((effect) => {
                player.runCommandAsync(`/effect ${player.name} ${effect.effectType} 0 0 true`);
            });
        }
    }
    static applyVisualEffects(worldEvent, player, stage) {
        const { visualEffects, blockVisualEffects } = worldEvent.effectOptions;
        const dimension = world.getDimension("overworld");
        const existingIntervals = WorldEvent.loopingIntervals.get(worldEvent.id);
        if (existingIntervals) {
            existingIntervals.forEach((interval) => system.clearRun(interval));
            WorldEvent.loopingIntervals.delete(worldEvent.id);
        }
        const intervals = [];
        if (stage === WorldEventStage.START && visualEffects?.onStart) {
            // Handle onStart visual effects
            visualEffects.onStart.particles?.forEach((particle) => {
                dimension.spawnParticle(particle, player.location);
            });
            visualEffects.onStart.sounds?.forEach((sound) => {
                dimension.playSound(sound, player.location);
            });
        }
        if (stage === WorldEventStage.IDLE && visualEffects?.onInterval) {
            // Handle onInterval visual effects
            visualEffects.onInterval.particles?.forEach((particleEffect) => {
                const intervalTime = particleEffect.interval > 0 ? particleEffect.interval : 20;
                const interval = system.runInterval(() => {
                    dimension.spawnParticle(particleEffect.type, player.location);
                }, intervalTime);
                intervals.push(interval);
            });
            visualEffects.onInterval.sounds?.forEach((soundEffect) => {
                const intervalTime = soundEffect.interval > 0 ? soundEffect.interval : 20;
                const interval = system.runInterval(() => {
                    dimension.playSound(soundEffect.type, player.location);
                }, intervalTime);
                intervals.push(interval);
            });
        }
        if (stage === WorldEventStage.END && visualEffects?.onEnd) {
            // Handle onEnd visual effects
            visualEffects.onEnd.particles?.forEach((particle) => {
                dimension.spawnParticle(particle, player.location);
            });
            visualEffects.onEnd.sounds?.forEach((sound) => {
                dimension.playSound(sound, player.location);
            });
        }
        if (intervals.length > 0) {
            WorldEvent.loopingIntervals.set(worldEvent.id, intervals);
        }
    }
    static applyEventEndEffects(worldEvent, location) {
        const { visualEffects } = worldEvent.effectOptions;
        const dimension = world.getDimension("overworld");
        if (visualEffects?.onEnd) {
            visualEffects.onEnd.particles?.forEach((particle) => {
                dimension.spawnParticle(particle, location);
            });
            visualEffects.onEnd.sounds?.forEach((sound) => {
                dimension.playSound(sound, location);
            });
        }
    }
    static countActiveEvents() {
        return WorldEvent.activeEvents.size;
    }
    static spawnParticles(worldEvent, location) {
        const { borderParticles } = worldEvent.effectOptions;
        if (borderParticles) {
            const intervals = [];
            const dimension = world.getDimension("overworld");
            borderParticles.forEach((particle) => {
                const intervalTime = particle.interval > 0 ? particle.interval : 20;
                const interval = system.runInterval(() => {
                    const positions = CustomVector3.createSphere(new CustomVector3(location.x, location.y, location.z), worldEvent.radius, particle.amount, true);
                    positions.forEach((pos) => {
                        try {
                            dimension.spawnParticle(particle.identifier, pos);
                        }
                        catch (e) { }
                    });
                }, intervalTime * 20);
                intervals.push(interval);
            });
            if (intervals.length > 0) {
                WorldEvent.loopingIntervals.set(worldEvent.id, intervals);
            }
        }
    }
}
WorldEvent.worldEvents = [];
WorldEvent.eventLocations = new Map();
WorldEvent.activeEvents = new Map();
WorldEvent.eventCooldowns = new Map();
WorldEvent.loopingIntervals = new Map();
