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

export class ChunkUtil {
    static #perDimension = {};

    dimension;
    #simulatedChunkCache = {};

    constructor(dimension) {
        this.dimension = dimension;
    }

    static isEntitySimulated(entity) {
        if(entity.typeId == "minecraft:player") return true;
        let dimension;
        try {
            dimension = entity.dimension;
        } catch(err) {
            //exception trying to access dimension, must be invalid
            return false;
        }
        return this.isLocationSimulated(dimension, entity.location);
    }

    static isLocationSimulated(dimension, loc) {
        return this.#forDimension(dimension).isLocationSimulated(loc);
    }

    isLocationSimulated(loc) {
        let chunkObj = ChunkUtil.#getChunkObjForLocation(loc);

        let cachedValue = this.#simulatedChunkCache[chunkObj.key];
        if(cachedValue != null) return cachedValue;

        let block = this.dimension.getBlock({x: loc.x, y: 0, z: loc.z});

        return this.#simulatedChunkCache[chunkObj.key] = block != undefined;
    }

    static #getChunkObjForLocation(loc) {
        var x = Math.floor(loc.x / 16);
        var z = Math.floor(loc.z / 16);
        return this.#createChunkObj(x, z);
    }
    static #createChunkObj(cx, cz) {
        return {
            x: cx,
            z: cz,
            key: `(${cx}, ${cz})`
        };
    }

    #clearChunkCache(tick) {
        tick ??= system.currentTick;
        this.#simulatedChunkCache = {};
    }
    
    static #forDimension(dimension) {
        dimension.scriptData ??= {};
        return dimension.scriptData["conduit:chunk_util"] ??= this.#perDimension[dimension.identifier] ??= new ChunkUtil(dimension);
    }

    static clearCaches() {
        let tick = system.currentTick;
        for(let key in this.#perDimension) {
            let value = this.#perDimension[key];
            value.#clearChunkCache(tick);
        }
    }
}

system.runInterval(()=>{
    ChunkUtil.clearCaches();
});