import { system, TicksPerSecond, world } from "@minecraft/server";
class PlayerManager {
    constructor() {
        this.cache = [];
        if (!PlayerManager.initialized) {
            this.onReady();
            PlayerManager.initialized = true;
        }
    }
    onReady() {
        world.afterEvents.playerJoin.subscribe((event) => this.onPlayerJoined(event.playerId));
        world.beforeEvents.playerLeave.subscribe((event) => this.onPlayerLeave(event.player));
        world.afterEvents.worldInitialize.subscribe(() => {
            if (this.cache.length === 0) {
                const players = world.getAllPlayers();
                players.forEach((player) => {
                    this.addPlayerToCache(player);
                });
            }
        });
    }
    onPlayerJoined(playerId) {
        function getPlayer() {
            return world.getEntity(playerId);
        }
        let player = undefined;
        let tries = 0;
        const i = system.runInterval(() => {
            if (player === undefined || !player.isValid()) {
                player = getPlayer();
                tries++;
            }
            else {
                this.addPlayerToCache(player);
                system.clearRun(i);
            }
        }, TicksPerSecond);
    }
    onPlayerLeave(player) {
        this.removePlayerFromCache(player);
    }
    addPlayerToCache(player) {
        const index = this.cache.findIndex(p => p.id === player.id);
        if (index === -1)
            this.cache.push(player);
    }
    removePlayerFromCache(player) {
        const index = this.cache.findIndex(p => p.id === player.id);
        if (index !== -1)
            this.cache.splice(index, 1);
    }
    static create() {
        return new PlayerManager();
    }
}
PlayerManager.initialized = false;
export const playerManager = PlayerManager.create();
let WORLD_READY = false;
world.afterEvents.worldInitialize.subscribe(() => { WORLD_READY = true; });
const MAIN_LOOP = system.runInterval(() => {
    if (!WORLD_READY)
        return;
    try {
        playerManager.cache.forEach((player) => {
            if (!player || !player.isValid()) {
                playerManager.removePlayerFromCache(player);
                return;
            }
            try {
                playerThread(player);
            }
            catch (error) { /*Catching out bounds error*/ }
        });
    }
    catch (error) {
        system.clearRun(MAIN_LOOP);
        throw Error(`Critical error occurred in main thread: ${error}`);
    }
}, TicksPerSecond);
const playerDataCache = new Map();
const playerThread = (player) => {
    const i = player.dimension.spawnEntity("pu_biomes:util", player.location);
    const biome = i.getProperty("pu_biomes:biome");
    const playerData = playerDataCache.get(player.id) || { biome: 0 };
    if (playerData.biome !== biome) {
        playerData.biome = biome;
        playerDataCache.set(player.id, playerData);
        BiomeChangedEventSignal.emit({ player: player, biome: biome });
    }
    i.remove();
    PlayerThreadImpulseEventSignal.emit({ player });
};
export class CustomWorld {
    constructor() {
        this.afterEvents = AfterEvents.create();
    }
    getBiomeName(biome) {
        switch (biome) {
            case 1: return "volcano";
            case 2: return "autumn";
            case 3: return "crystal_caves";
            case 4: return "sandstone_caves";
            case 5: return "enchanted";
            case 6: return "horror";
            case 7: return "lavander";
            case 8: return "lunar";
            case 9: return "mushroom";
            case 10: return "sky_islands";
            case 11: return "toxic";
            case 12: return "whisper";
            default: return undefined;
        }
    }
    static create() { return new CustomWorld(); }
}
export class AfterEvents {
    constructor() {
        this.BiomeChangedEvent = BiomeChangedEventSignal.create();
        this.PlayerThreadImpulseEvent = PlayerThreadImpulseEventSignal.create();
        this.BiomeChangedEvent = BiomeChangedEventSignal.create();
    }
    static create() {
        return new AfterEvents();
    }
}
export class PlayerThreadImpulseEventSignal {
    constructor() { }
    static create() {
        return new PlayerThreadImpulseEventSignal();
    }
    subscribe(callback) {
        PlayerThreadImpulseEventSignal.subscribers.add(callback);
        return callback;
    }
    unsubscribe(callback) {
        PlayerThreadImpulseEventSignal.subscribers.delete(callback);
    }
    static emit(event) {
        for (const callback of this.subscribers) {
            try {
                callback(event);
            }
            catch (error) {
                console.error("Error in PlayerThreadImpulseEvent global subscriber:", error);
            }
        }
    }
}
PlayerThreadImpulseEventSignal.subscribers = new Set();
export class PlayerThreadImpulseEvent {
    constructor(player) {
        this.player = player;
    }
    static create(player) {
        return new PlayerThreadImpulseEvent(player);
    }
}
export class BiomeChangedEventSignal {
    constructor() { }
    static create() {
        return new BiomeChangedEventSignal();
    }
    subscribe(callback) {
        BiomeChangedEventSignal.subscribers.add(callback);
        return callback;
    }
    unsubscribe(callback) {
        BiomeChangedEventSignal.subscribers.delete(callback);
    }
    static emit(event) {
        for (const callback of this.subscribers) {
            try {
                callback(event);
            }
            catch (error) {
                console.error("Error in BiomeChangedEvent global subscriber:", error);
            }
        }
    }
}
BiomeChangedEventSignal.subscribers = new Set();
export class BiomeChangedEvent {
    constructor(player, biome) {
        this.player = player;
        this.biome = biome;
    }
    static create(player, biome) {
        return new BiomeChangedEvent(player, biome);
    }
}
export const customWorld = CustomWorld.create();
