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

/**
 * A class that triggers events when the player enters/leaves one of the new biomes.
 */
class BiomeObserver {
    /** @type {Map<Player, string>} */
    #playerData = new Map();
    /** @type {Array<function(Player, string): void>} */
    #subscriptions = [];

    constructor() {
        system.runInterval(this.#run.bind(this), 15);
    }

    /**
     * Subscribes to biome change events.
     * @param {function(Player, string): void} callback - The callback function to be called when the biome changes. The callback receives the new biome as a string.
     */
    subscribeToBiomeChange(callback) {
        this.#subscriptions.push(callback);
    }

    getPlayerBiome(player) {
        return this.#playerData.get(player);
    }


    #run() {
        world.getAllPlayers().forEach(player => {

            if (player.dimension.id !== 'minecraft:overworld') return;
            const currentBiome = this.#checkPlayerBiome(player);
            const previousBiome = this.#playerData.get(player);
            if (currentBiome !== previousBiome) {
                this.#subscriptions.forEach(subscription => subscription(player, currentBiome));
                this.#playerData.set(player, currentBiome);
            }
        });
    }

    /**
     * Checks the biome that the player is in
     * @param {Player} player 
     * @returns {string|undefined} The biome that the player is in, or undefined if the player is not in a custom biome.
     */
    #checkPlayerBiome(player) {
        const dimension = player.dimension;
        const biomeIdentifierBlock = dimension.getBlock({ ...player.location, y: 319 });
        if (!biomeIdentifierBlock || !biomeIdentifierBlock.typeId.startsWith('ecbl_bc:biome_identifier_')) return 'vanilla';
        return biomeIdentifierBlock.typeId.split('_')[3];
    }
}

export default new BiomeObserver();