import { Block, Dimension, Entity, system, world } from "@minecraft/server";
import { EntityTypeIds } from "../utils/entityTypesIds";
import { EntityProperites } from "../utils/entityProperties";
import { WorldProperties } from "../../world/utils/worldProperties";
import { EntityHelper } from "../utils/entityHelper";
import { testing } from "../../utils/systemHelper";

export const DUMMY = {
    _typeId: "piki_beyondsurvival:dummy",
    _attentionEvent: "piki_beyondsurvival:attention",
    _despawnEvent: "piki_beyondsurvival:despawn",

    // Entry Points
    /**
     * 
     * @param {Entity} dummy 
     * @param {string} eventId
     */
    hasNoAttention(dummy, eventId) {
        if ((dummy.typeId != this._typeId && eventId != this._attentionEvent) || !dummy.isValid()) return

        const lastLoadedTimestamp = dummy.getDynamicProperty(EntityProperites.lastLoadTimestamp) ?? new Date(0).getTime();
        const worldLastLoadedTimestamp = world.getDynamicProperty(WorldProperties.lastLoadedTimestamp)
        const isReloaded = worldLastLoadedTimestamp != lastLoadedTimestamp;
        return isReloaded
    },

    // Helper Methods
    /**
     * 
     * @param {Entity} dummy 
     */
    didMove(dummy, lastLocation) {
        const currentLocation = dummy.location

        return (lastLocation.x != currentLocation.x ||
                lastLocation.y != currentLocation.y ||
                lastLocation.z != currentLocation.z
        )
    },

    /**
     * 
     * @param {Entity} dummy 
     */
    reload(dummy) {
        const worldLastLoadedTimestamp = world.getDynamicProperty(WorldProperties.lastLoadedTimestamp)
        dummy.setDynamicProperty(EntityProperites.lastLoadTimestamp, worldLastLoadedTimestamp)

        EntityHelper.resetProperties(dummy)

        this.preventTeleport(dummy)
    },

    /**
     * 
     * @param {Entity} dummy 
     */
    preventTeleport(dummy) {
        const teleportWatcher = system.runInterval(() => {
            if (!dummy.isValid()) {
                system.clearRun(teleportWatcher)
                return
            }

            let permanentLocation = dummy.getDynamicProperty(EntityProperites.permanentLocation)
            
            if (!permanentLocation) {
                dummy.setDynamicProperty(EntityProperites.permanentLocation, dummy.location)

                permanentLocation = dummy.location

            }

            if (this.didMove(dummy, permanentLocation)) {
                dummy.teleport(permanentLocation, {checkForBlocks: false})
            }
        })
    },

    /**
     * 
     * @param {Entity} dummy 
     * @returns 
     */
    getType(dummy) {
        return dummy.getDynamicProperty(EntityProperites.dummyType);
    },

    /**
     * 
     * @param {Dimension} dimension 
     * @param {import("@minecraft/server").Vector3} location 
     * @param {string} type 
     * @param {boolean} preventTeleport Defaults to true
     */
    summon(dimension, location, type, preventTeleport = true) {
        const entity = dimension.spawnEntity(EntityTypeIds.dummy, {
            x: Math.trunc(location.x) + 0.5,
            y: Math.trunc(location.y),
            z: Math.trunc(location.z) + 0.5
        })
        
        const lastReloadTime = world.getDynamicProperty(WorldProperties.lastLoadedTimestamp) 

        entity.setDynamicProperty(EntityProperites.dummyType, type)
        entity.setDynamicProperty(EntityProperites.lastLoadTimestamp, lastReloadTime)

        if (preventTeleport) this.preventTeleport(entity)
    },
    
    /**
     * 
     * @param {Entity|Block} dummy 
     */
    kill(dummy, reason = undefined) {
        system.run(() => {
            let dummyEntity;
            if (dummy instanceof Entity) dummyEntity = dummy
            else dummyEntity = dummy.dimension.getEntities({type: this._typeId, location: dummy.location})[0]
    
            if (!dummyEntity.isValid()) return

            const {x, y, z} = dummy.location
    
            // if (reason) testing.info("Dummy despawn at", x, y, z, "due to", reason)
            dummyEntity.triggerEvent(this._despawnEvent)
        })
    }
}