import * as mc from "@minecraft/server"
import * as utilFunction from "./cyd_mp_util"
import * as cutification from "./cyd_mp_cutification"
import * as main from "./cyd_mp_main"
import * as sounds from "./cyd_mp_mobSounds"

const OVERWORLD = mc.world.getDimension("overworld");
const NETHER = mc.world.getDimension("nether");
const THE_END = mc.world.getDimension("the end");



const SOUND_EMOTION_HAPPY = "cyd_mp.emotion_happy";
const SOUND_EMOTION_NEGATIVE = "cyd_mp.emotion_negative";
const SOUND_QUEST_COMPLETE = "cyd_mp.quest_complete";
const SOUND_QUEST_PING = "cyd_mp.quest_ping";
const DEFAULT_MOB_EAT = "random.eat";
const SOUND_OPTIONS = { pitch: 1.0, volume: 1.0, };

const petFoodMap = {
    "cyd_mp:cute_bat": ["minecraft:glow_berries"],
    "cyd_mp:cute_bee": ["minecraft:dandelion", "minecraft:poppy", "minecraft:blue_orchid", "minecraft:allium", "minecraft:azure_bluet", "minecraft:red_tulip", "minecraft:orange_tulip", "minecraft:white_tulip", "minecraft:pink_tulip", "minecraft:oxeye_daisy", "minecraft:cornflower", "minecraft:lily_of_the_valley", "minecraft:torchflower"],
    "cyd_mp:cute_blaze": ["minecraft:glowstone_dust"],
    "cyd_mp:cute_cat": ["minecraft:cooked_salmon", "minecraft:pufferfish", "minecraft:salmon", "minecraft:cooked_fish", "minecraft:fish", "minecraft:tropical_fish"],
    "cyd_mp:cute_cave_spider": ["minecraft:potion:25"], // how to do potion of poision?
    "cyd_mp:cute_chicken": ["minecraft:wheat_seeds"],
    "cyd_mp:cute_cow": ["minecraft:wheat"],
    "cyd_mp:cute_creeper": ["minecraft:gunpowder"],
    "cyd_mp:cute_dolphin": ["minecraft:cooked_salmon", "minecraft:pufferfish", "minecraft:salmon", "minecraft:cooked_fish", "minecraft:fish", "minecraft:tropical_fish"],
    "cyd_mp:cute_donkey": ["minecraft:sugar"],
    "cyd_mp:cute_drowned": ["minecraft:fish"],
    "cyd_mp:cute_elder_guardian": ["minecraft:pufferfish"],
    "cyd_mp:cute_ender_dragon": ["minecraft:ender_pearl"],
    "cyd_mp:cute_enderman": ["minecraft:pumpkin", "minecraft:chorus_fruit"],
    "cyd_mp:cute_endermite": ["minecraft:chorus_fruit"],
    "cyd_mp:cute_evoker": ["minecraft:emerald"],
    "cyd_mp:cute_fox": ["minecraft:sweet_berries"],
    "cyd_mp:cute_ghast": ["minecraft:blaze_powder"],
    "cyd_mp:cute_guardian": ["minecraft:salmon"],
    "cyd_mp:cute_hoglin": ["minecraft:sugar"],
    "cyd_mp:cute_horse": ["minecraft:sugar"],
    "cyd_mp:cute_zombie_horse": ["minecraft:sugar"],
    "cyd_mp:cute_skeleton_horse": ["minecraft:sugar"],
    "cyd_mp:cute_husk": ["minecraft:rotten_flesh"],
    "cyd_mp:cute_iron_golem": ["minecraft:poppy"],
    "cyd_mp:cute_llama": ["minecraft:hay_block"],
    "cyd_mp:cute_magma_cube": ["minecraft:lava_bucket"],
    "cyd_mp:cute_mooshroom": ["minecraft:brown_mushroom", "minecraft:red_mushroom"],
    "cyd_mp:cute_mule": ["minecraft:sugar"],
    "cyd_mp:cute_ocelot": ["minecraft:cooked_salmon", "minecraft:salmon"],
    "cyd_mp:cute_panda": ["minecraft:bamboo"],
    "cyd_mp:cute_parrot": ["minecraft:melon_seeds"],
    "cyd_mp:cute_phantom": ["minecraft:clock"],
    "cyd_mp:cute_pig": ["minecraft:carrot"],
    "cyd_mp:cute_piglin": ["minecraft:gold_ingot"],
    "cyd_mp:cute_piglin_brute": ["minecraft:gold_ingot"],
    "cyd_mp:cute_pillager": ["minecraft:emerald"],
    "cyd_mp:cute_polar_bear": ["minecraft:salmon"],
    "cyd_mp:cute_rabbit": ["minecraft:carrot"],
    "cyd_mp:cute_ravager": ["minecraft:chicken"],
    "cyd_mp:cute_sheep": ["minecraft:wheat"],
    "cyd_mp:cute_shulker": ["minecraft:ender_pearl"],
    "cyd_mp:cute_silverfish": ["minecraft:smooth_stone"],
    "cyd_mp:cute_skeleton": ["minecraft:bone_meal"],
    "cyd_mp:cute_slime": ["minecraft:slime_ball"],
    "cyd_mp:cute_snow_golem": ["minecraft:snowball"],
    "cyd_mp:cute_spider": ["minecraft:potion:25"], // how to do potion of poision?
    "cyd_mp:cute_squid": ["minecraft:fish"],
    "cyd_mp:cute_glow_squid": ["minecraft:fish"],
    "cyd_mp:cute_stray": ["minecraft:bone_meal"],
    "cyd_mp:cute_strider": ["minecraft:warped_fungus"],
    "cyd_mp:cute_turtle": ["minecraft:seagrass"],
    "cyd_mp:cute_vex": ["minecraft:iron_sword"],
    "cyd_mp:cute_vindicator": ["minecraft:emerald"],
    "cyd_mp:cute_witch": ["minecraft:redstone"],
    "cyd_mp:cute_wither": ["minecraft:wither_rose"],
    "cyd_mp:cute_wither_skeleton": ["minecraft:wither_rose"],
    "cyd_mp:cute_wolf": ["minecraft:bone"],
    "cyd_mp:cute_zoglin": ["minecraft:crimson_fungus"],
    "cyd_mp:cute_zombie": ["minecraft:rotten_flesh"],
    "cyd_mp:cute_zombie_piglin": ["minecraft:gold_nugget"],
    "cyd_mp:cute_axolotl": ["minecraft:tropical_fish"],
    "cyd_mp:cute_goat": ["minecraft:hay_block"],
    "cyd_mp:cute_allay": ["minecraft:amethyst_shard"],
    "cyd_mp:cute_sniffer": ["minecraft:dandelion", "minecraft:poppy", "minecraft:blue_orchid", "minecraft:allium", "minecraft:azure_bluet", "minecraft:red_tulip", "minecraft:orange_tulip", "minecraft:white_tulip", "minecraft:pink_tulip", "minecraft:oxeye_daisy", "minecraft:cornflower", "minecraft:lily_of_the_valley", "minecraft:torchflower"],
    "cyd_mp:cute_camel": ["minecraft:cactus"],
    "cyd_mp:cute_warden": ["minecraft:sculk"],
    "cyd_mp:cute_tadpole": ["minecraft:slime_ball"],
    "cyd_mp:cute_frog": ["minecraft:magma_cream"],
    "cyd_mp:cute_armadillo": ["minecraft:spider_eye"],
    "cyd_mp:cute_creaking": ["minecraft:stick"],
    "cyd_mp:cute_breeze": ["minecraft:phantom_membrane"],
    "cyd_mp:cute_bogged": ["minecraft:brown_mushroom", "minecraft:red_mushroom"]
};

export function endermanDamageTeleport() {
    mc.world.afterEvents.entityHurt.subscribe((eventData) => {
        const damagedEntity = eventData.hurtEntity; // The entity that was damaged

        // Log or handle the event
        if (damagedEntity.typeId == "cyd_mp:cute_enderman" && utilFunction.getRandomInt(1, 100) <= 20) {
            damagedEntity.dimension.spawnParticle("cyd_mp:mini_ender_teleport", damagedEntity.location);
            utilFunction.teleportEntityToRandomBlock(damagedEntity, 3);
        }
    });
}

export function endermanArrowTeleport() {
    let overworld_enderman = OVERWORLD.getEntities({
        type: "cyd_mp:cute_enderman"
    });
    let nether_enderman = NETHER.getEntities({
        type: "cyd_mp:cute_enderman"
    });
    let the_end_enderman = THE_END.getEntities({
        type: "cyd_mp:cute_enderman"
    });
    const teleportMatchingEntities = (entities) => {
        entities.forEach(nPEntity => {
            if (utilFunction.entityDetectArrow(nPEntity, 3)) {
                nPEntity.dimension.spawnParticle("cyd_mp:mini_ender_teleport", nPEntity.location);
                utilFunction.teleportEntityToRandomBlock(nPEntity, 3);
            }
        });
    };
    teleportMatchingEntities(overworld_enderman);
    teleportMatchingEntities(nether_enderman);
    teleportMatchingEntities(the_end_enderman);
}

export function breezeProjectileReflect() {
    let overworld_entity = OVERWORLD.getEntities({
        type: "cyd_mp:cute_breeze"
    });
    let nether_entity = NETHER.getEntities({
        type: "cyd_mp:cute_breeze"
    });
    let the_end_entity = THE_END.getEntities({
        type: "cyd_mp:cute_breeze"
    });
    const teleportMatchingEntities = (entities) => {
        entities.forEach(nPEntity => {
            let arrows = utilFunction.entityDetectAllArrow(nPEntity, 3);
            let smFireball = utilFunction.entityDetectAllSmallFireball(nPEntity, 3);
            let lgFireball = utilFunction.entityDetectAllLargeFireball(nPEntity, 3);
            if (arrows.length > 0) {
                arrows.forEach(nPProj => {
                    utilFunction.returnProjectile(nPProj);
                });
            }
            if (smFireball.length > 0) {
                smFireball.forEach(nPProj => {
                    utilFunction.returnProjectile(nPProj);
                });
            }
            if (lgFireball.length > 0) {
                lgFireball.forEach(nPProj => {
                    utilFunction.returnProjectile(nPProj);
                });
            }
        });
    };
    teleportMatchingEntities(overworld_entity);
    teleportMatchingEntities(nether_entity);
    teleportMatchingEntities(the_end_entity);
}

export function initMobTracking2() {
    let overworld_pets = OVERWORLD.getEntities({
        families: ["pet"]
    });
    let nether_pets = NETHER.getEntities({
        families: ["pet"]
    });
    let the_end_pets = THE_END.getEntities({
        families: ["pet"]
    });

    const initTracking = (entities) => {
        entities.forEach(nPEntity => {
            startTrackingMob(nPEntity);
        });
    }
    initTracking(overworld_pets);
    initTracking(nether_pets);
    initTracking(the_end_pets);
}

function startTrackingMob(mob) {
    if (!mob.getDynamicProperty("cyd_mp_last_pos")) {
        mob.setDynamicProperty("cyd_mp_last_pos", mob.location);
    }
}

// determine how many blocks the mob has traveled with owner
export function travelDistanceTracker() {
    let overworld_pets = OVERWORLD.getEntities({
        families: ["pet"]
    });
    let nether_pets = NETHER.getEntities({
        families: ["pet"]
    });
    let the_end_pets = THE_END.getEntities({
        families: ["pet"]
    });

    const incrementXp = (entities) => {
        entities.forEach(nPEntity => {
            let tameComponent = nPEntity.getComponent(mc.EntityComponentTypes.Tameable);
            if (tameComponent) {
                let player = tameComponent.tamedToPlayer;
                if (tameComponent.isTamed) {
                    let lastPosition = nPEntity.getDynamicProperty("cyd_mp_last_pos");
                    if (lastPosition) {
                        const currentPosition = nPEntity.location;
                        const dx = Math.abs(currentPosition.x - lastPosition.x);
                        const dy = Math.abs(currentPosition.y - lastPosition.y);
                        const dz = Math.abs(currentPosition.z - lastPosition.z);

                        const distance = dx + dy + dz;

                        if (distance >= 30) {
                            nPEntity.setDynamicProperty("cyd_mp_last_pos", currentPosition); // Update last position

                            nPEntity.triggerEvent("evt:increase_xp_current");
                        }
                    }
                }
            }
        });
    }
    incrementXp(overworld_pets);
    incrementXp(nether_pets);
    incrementXp(the_end_pets);
}


export function countEmotionTime() {

    let overworld_pets = OVERWORLD.getEntities({
        families: ["pet"]
    });
    let nether_pets = NETHER.getEntities({
        families: ["pet"]
    });
    let the_end_pets = THE_END.getEntities({
        families: ["pet"]
    });

    const incrementTimer = (entities) => {
        entities.forEach(nPEntity => {
            let tameComponent = nPEntity.getComponent(mc.EntityComponentTypes.Tameable);
            if (tameComponent && tameComponent.isTamed) {
                let emotionTime = nPEntity.getDynamicProperty("cyd_mp_emotionTime");

                let isHungry = nPEntity.getProperty("property:hungry");
                let isTired = nPEntity.getProperty("property:tired");
                if (isHungry || isTired) {
                    if (emotionTime >= 60) {
                        if (isHungry || isTired) {
                            nPEntity.addEffect('slowness', 1 * 20, { amplifier: 255, showParticles: false });
                        }
                    } else {
                        nPEntity.setDynamicProperty("cyd_mp_emotionTime", emotionTime + 1);
                        if (isHungry || isTired) {
                            nPEntity.addEffect('slowness', 1 * 20, { amplifier: 2, showParticles: false });
                        }
                    }
                }
            }
        });
    }

    incrementTimer(overworld_pets);
    incrementTimer(nether_pets);
    incrementTimer(the_end_pets);
}

// make a mob feel something
// random timer 5 - 10 minutes as dynamic property?
function mobEmotionTimer(entity) {
    let time = utilFunction.getRandomInt(300, 600); // 300,600
    entity.setDynamicProperty("cyd_mp_emotionTimer", time);
}
function mobEmotionTime(entity) {
    entity.setDynamicProperty("cyd_mp_emotionTime", 0);
}
// tick timer down every 20 ticks
export function emotionTickDownTimer() {
    let overworld_pets = OVERWORLD.getEntities({
        families: ["pet"]
    });
    let nether_pets = NETHER.getEntities({
        families: ["pet"]
    });
    let the_end_pets = THE_END.getEntities({
        families: ["pet"]
    });

    const decrementTimer = (entities) => {
        entities.forEach(nPEntity => {
            let tameComponent = nPEntity.getComponent(mc.EntityComponentTypes.Tameable);
            if (tameComponent && tameComponent.isTamed) {
                let timeRemaining = nPEntity.getDynamicProperty("cyd_mp_emotionTimer");
                let emotionTime = nPEntity.getDynamicProperty("cyd_mp_emotionTime");
                if (timeRemaining && timeRemaining > 0) {
                    nPEntity.setDynamicProperty("cyd_mp_emotionTimer", timeRemaining - 1);
                }
                if (!timeRemaining) {
                    mobEmotionTimer(nPEntity);
                }
                if (!emotionTime) {
                    mobEmotionTime(nPEntity);
                }
                if (timeRemaining == 0) {
                    if (utilFunction.isEntityHappy(nPEntity)) {
                        let player = tameComponent.tamedToPlayer;
                        mobEmotion(nPEntity, player);
                    }
                }
            }
        });
    }

    decrementTimer(overworld_pets);
    decrementTimer(nether_pets);
    decrementTimer(the_end_pets);
}
// make them feel tired or hungry - leaving off scared for now
function mobEmotion(entity, player) {
    // entity.dimension.spawnParticle("cyd_mp:exclamation_mark", entity.location);
    // feel random emotion
    let questChance = utilFunction.getRandomInt(0, 10);
    let emotionIndex = utilFunction.getRandomInt(0, 1);
    if (questChance == 0) {
        // get random food that mob wants
        let petFoods = petFoodMap[entity.typeId];
        let foodIndex = utilFunction.getRandomInt(0, petFoods.length - 1);
        let desiredFood = petFoods[foodIndex];
        entity.setDynamicProperty("cyd_mp_desireFood", desiredFood);
        entity.triggerEvent("evt:is_quest");
        player.playSound(SOUND_QUEST_PING, SOUND_OPTIONS);
        player.sendMessage(`${main.formatEntityName(entity.typeId)} wants ${main.formatVanillaName(desiredFood)}`);
        entity.triggerEvent(`evt:food_${foodIndex + 1}`);
    } else {
        if (emotionIndex == 0) {
            entity.triggerEvent("evt:is_tired");
            player.playSound(SOUND_EMOTION_NEGATIVE, SOUND_OPTIONS);
            // player.playSound(SOUND_QUEST_PING, SOUND_OPTIONS);
            player.sendMessage(`${main.formatEntityName(entity.typeId)} is tired.`);
        } else if (emotionIndex == 1) {
            entity.triggerEvent("evt:is_hungry");
            player.playSound(SOUND_EMOTION_NEGATIVE, SOUND_OPTIONS);
            // player.playSound(SOUND_QUEST_PING, SOUND_OPTIONS);
            player.sendMessage(`${main.formatEntityName(entity.typeId)} is hungry.`);
        }
        // else if (emotionIndex == 2) {
        //     entity.triggerEvent("evt:is_scared");
        //     player.playSound(SOUND_EMOTION_NEGATIVE, SOUND_OPTIONS);
        //     // player.playSound(SOUND_QUEST_PING, SOUND_OPTIONS);
        //     player.sendMessage(`${main.formatEntityName(entity.typeId)} is scared.`);
        // }
    }
}
// on player interact with preferred food, make mob happy and increase xp
export function foodUseListener() {
    mc.world.afterEvents.itemUse.subscribe((eventData) => {
        let player = eventData.source;
        let itemUse = eventData.itemStack;
        if (itemUse === undefined) return;

        const useFood = Object.values(petFoodMap).some(array => array.includes(itemUse.typeId));

        if (useFood) {
            foodQuest(player, itemUse.typeId);
        }
    });
}

function foodQuest(player, usedFood) {
    let firstMob = cutification.getFirstCuteMobInView(player, 10);
    if (firstMob) {
        let isQuest = firstMob.getProperty("property:quest");
        let isHungry = firstMob.getProperty("property:hungry");
        let isScared = firstMob.getProperty("property:scared");

        if (isQuest) {
            let desiredFood = firstMob.getDynamicProperty("cyd_mp_desireFood");
            let petFoods = petFoodMap[firstMob.typeId];
            if (petFoods) {
                if (desiredFood) {
                    if (usedFood == desiredFood) {
                        // stuff here
                        player.sendMessage(`${main.formatEntityName(firstMob.typeId)} is happy!`)
                        firstMob.dimension.spawnParticle("cyd_mp:heart_rise", firstMob.location);
                        firstMob.triggerEvent("evt:set_happy");
                        firstMob.triggerEvent("evt:increase_xp_current");
                        firstMob.triggerEvent("evt:happy_flag_on");
                        firstMob.setDynamicProperty("cyd_mp_desireFood", null);
                        firstMob.setDynamicProperty("cyd_mp_emotionTimer", null);
                        // player.playSound(SOUND_EMOTION_HAPPY, SOUND_OPTIONS);
                        player.playSound(SOUND_QUEST_COMPLETE, SOUND_OPTIONS);
                        player.playSound(DEFAULT_MOB_EAT, SOUND_OPTIONS);
                        firstMob.triggerEvent("evt:food_0");
                    } else {
                        player.sendMessage(`${main.formatEntityName(firstMob.typeId)} does not want this.`);
                    }
                }
            }
        }
        if (isHungry || isScared) {
            let petFoods = petFoodMap[firstMob.typeId];
            if (petFoods) {
                if (petFoods.includes(usedFood) || usedFood == "cyd_mp:pet_food") {
                    player.sendMessage(`${main.formatEntityName(firstMob.typeId)} is happy!`)
                    firstMob.dimension.spawnParticle("cyd_mp:heart_rise", firstMob.location);
                    firstMob.triggerEvent("evt:set_happy");
                    firstMob.triggerEvent("evt:increase_xp_current");
                    firstMob.triggerEvent("evt:happy_flag_on");
                    firstMob.triggerEvent("evt:fear_none");
                    firstMob.setDynamicProperty("cyd_mp_emotionTimer", null);
                    firstMob.setDynamicProperty("cyd_mp_emotionTime", null);
                    player.playSound(SOUND_EMOTION_HAPPY, SOUND_OPTIONS);
                    player.playSound(DEFAULT_MOB_EAT, SOUND_OPTIONS);
                } else {
                    player.sendMessage(`${main.formatEntityName(firstMob.typeId)} does not want this.`);
                }
            }
        }
    }
}

function parrotSoundTimer(entity) {
    let time = utilFunction.getRandomInt(60, 120);
    entity.setDynamicProperty("cyd_mp_soundTimer", time);
}

export function parrotTickDownTimer() {
    let overworld_pets = OVERWORLD.getEntities({
        type: "cyd_mp:cute_parrot"
    });
    let nether_pets = NETHER.getEntities({
        type: "cyd_mp:cute_parrot"
    });
    let the_end_pets = THE_END.getEntities({
        type: "cyd_mp:cute_parrot"
    });

    const decrementTimer = (entities) => {
        entities.forEach(nPEntity => {
            let tameComponent = nPEntity.getComponent(mc.EntityComponentTypes.Tameable);
            if (tameComponent.isTamed) {
                let timeRemaining = nPEntity.getDynamicProperty("cyd_mp_soundTimer");
                let player = tameComponent.tamedToPlayer;
                if (timeRemaining && timeRemaining > 0) {
                    nPEntity.setDynamicProperty("cyd_mp_soundTimer", timeRemaining - 1);
                }
                if (!timeRemaining) {
                    parrotSoundTimer(nPEntity);
                }
                if (timeRemaining == 0) {
                    parrotSound(player, nPEntity);
                }
            }
        });
    }

    decrementTimer(overworld_pets);
    decrementTimer(nether_pets);
    decrementTimer(the_end_pets);
}

function parrotSound(player, entity) {
    let nearbyMobs = utilFunction.entityDetectNearbyMobs(entity, 50);
    if (nearbyMobs.length > 0) {
        // stuff here
        // pick random mob
        let randomIndex = utilFunction.getRandomInt(0, nearbyMobs.length - 1);
        let selectedMob = nearbyMobs[randomIndex];
        // play its sound
        playEntitySound(player, selectedMob, "ambient");
        // remove soundTimer
        entity.setDynamicProperty("cyd_mp_soundTimer", null);
    }
}

function playEntitySound(player, entity, soundType) {
    if (!entity || !entity.isValid()) {
        return;
    }

    const entityName = entity.typeId.split(":")[1];
    const entitySound = sounds.soundData.entities[entityName];

    if (!entitySound) {
        return;
    }

    const soundEvent = entitySound.events[soundType];
    if (!soundEvent) {
        return;
    }

    const randomPitch = Math.random() * (entitySound.pitch[1] - entitySound.pitch[0]) + entitySound.pitch[0];
    const volume = entitySound.volume;

    // const { x, y, z } = parrot.location;
    // if (x == null || y == null || z == null) {
    //     console.error("Invalid entity location coordinates:", parrot.location);
    //     return;
    // }

    // Play the sound
    player.playSound(`minecraft:${soundEvent}`, SOUND_OPTIONS);
}

export function slimeDeath() {
    mc.world.afterEvents.entityDie.subscribe((eventData) => {
        const deadEntity = eventData.deadEntity;

        if (!deadEntity) return; // Ensure there's a valid dead entity

        // Check if the dead entity is a mob (not a player or item)
        if (deadEntity.typeId == "cyd_mp:cute_slime" && !deadEntity.hasTag("cyd_mp_dup")) {
            // slime died, summon two baby slimes here
            let tameComponent = deadEntity.getComponent(mc.EntityComponentTypes.Tameable);
            if (tameComponent) {
                let player = tameComponent.tamedToPlayer;

                if (player) {
                    const se1 = player.dimension.spawnEntity("cyd_mp:cute_slime", {
                        x: deadEntity.location.x,
                        y: deadEntity.location.y,
                        z: deadEntity.location.z,
                    });
                    const se2 = player.dimension.spawnEntity("cyd_mp:cute_slime", {
                        x: deadEntity.location.x,
                        y: deadEntity.location.y,
                        z: deadEntity.location.z,
                    });
                    se1.triggerEvent("evt:baby");
                    se2.triggerEvent("evt:baby");
                    se1.addTag("cyd_mp_dup");
                    se2.addTag("cyd_mp_dup");
                    let se1TameComponent = se1.getComponent(mc.EntityComponentTypes.Tameable);
                    let se2TameComponent = se2.getComponent(mc.EntityComponentTypes.Tameable);
                    se1TameComponent.tame(player);
                    se2TameComponent.tame(player);
                }
            }
        }
    });
}

export function shouldPlayParticle() {
    let overworld_players = OVERWORLD.getPlayers();
    let nether_players = NETHER.getPlayers();
    let the_end_players = THE_END.getPlayers();

    const playParticle = (entities) => {
        entities.forEach(nPEntity => {
            let equipmentComponent = nPEntity.getComponent(mc.EntityComponentTypes.Equippable);
            if (equipmentComponent) {
                const mainHandEquipment = equipmentComponent.getEquipment(mc.EquipmentSlot.Mainhand);
                if ((mainHandEquipment && mainHandEquipment.typeId === "cyd_mp:skin_tool")) {
                    // stuff here
                    let nearbyPets = utilFunction.entityDetectNearbyPets(nPEntity, 0, 10);
                    let distantPets = utilFunction.entityDetectNearbyPets(nPEntity, 11, 20);
                    nearbyPets.forEach(nBPet => {
                        let tameComponent = nBPet.getComponent(mc.EntityComponentTypes.Tameable);
                        if (tameComponent && tameComponent.isTamed && tameComponent.tamedToPlayer == nPEntity) {
                            let displayParticle = nBPet.getProperty("property:particle_display");
                            if (displayParticle == false) {
                                nBPet.triggerEvent("evt:particle_display_on");
                            }
                        }
                    });
                    distantPets.forEach(nBPet => {
                        let tameComponent = nBPet.getComponent(mc.EntityComponentTypes.Tameable);
                        if (tameComponent && tameComponent.isTamed && tameComponent.tamedToPlayer == nPEntity) {
                            let displayParticle = nBPet.getProperty("property:particle_display");
                            if (displayParticle == true) {
                                nBPet.triggerEvent("evt:particle_display_off");
                            }
                        }
                    });
                } else {
                    // stuff here
                    let nearbyPets = utilFunction.entityDetectNearbyPets(nPEntity, 0, 5);
                    let distantPets = utilFunction.entityDetectNearbyPets(nPEntity, 6, 10);
                    nearbyPets.forEach(nBPet => {
                        let tameComponent = nBPet.getComponent(mc.EntityComponentTypes.Tameable);
                        if (tameComponent && tameComponent.isTamed && tameComponent.tamedToPlayer == nPEntity) {
                            let displayParticle = nBPet.getProperty("property:particle_display");
                            if (displayParticle == true) {
                                nBPet.triggerEvent("evt:particle_display_off");
                            }
                        }
                    });
                    distantPets.forEach(nBPet => {
                        let tameComponent = nBPet.getComponent(mc.EntityComponentTypes.Tameable);
                        if (tameComponent && tameComponent.isTamed && tameComponent.tamedToPlayer == nPEntity) {
                            let displayParticle = nBPet.getProperty("property:particle_display");
                            if (displayParticle == true) {
                                nBPet.triggerEvent("evt:particle_display_off");
                            }
                        }
                    });
                }
            }
        });
    }
    playParticle(overworld_players);
    playParticle(nether_players);
    playParticle(the_end_players);
}

export function creakingDamageable() {
    // 3 hits within 3 seconds make the creaking damageable
    let timeWindow = 3000; // 3 seconds time in milliseconds
    let requiredHits = 3; // number of hits required
    const trackedCreaking = new Map();
    mc.world.afterEvents.entityHitEntity.subscribe((eventData) => {
        const damagedEntity = eventData.hitEntity; // The entity that was damaged

        // Log or handle the event
        if (damagedEntity.typeId == "cyd_mp:cute_creaking") {
            const entityId = damagedEntity.id;
            const currentTime = Date.now();
            damagedEntity.dimension.spawnParticle("cyd_mp:creaking_hit", damagedEntity.location);
            if (!trackedCreaking.has(entityId)) {
                trackedCreaking.set(entityId, [currentTime]);
            } else {
                const hitTimestamps = trackedCreaking.get(entityId);
                hitTimestamps.push(currentTime);

                // Filter timestamps to include only those within the time window
                const recentHits = hitTimestamps.filter((timestamp) => currentTime - timestamp <= timeWindow);
                trackedCreaking.set(entityId, recentHits);

                // Check if the required number of hits occurred within the time window
                if (recentHits.length >= requiredHits) {
                    // Trigger the damage event for the creaking
                    damagedEntity.triggerEvent("evt:damage_on");
                    damagedEntity.dimension.spawnParticle("cyd_mp:creaking_heart_explode_1", damagedEntity.location);
                    damagedEntity.dimension.spawnParticle("cyd_mp:creaking_heart_explode_2", damagedEntity.location);

                    // Remove the entity from the map to reset tracking
                    trackedCreaking.delete(entityId);
                }
            }
        }
    });
}

export function ironGolemFling() {
    mc.world.afterEvents.entityHitEntity.subscribe((eventData) => {
        const damagedEntity = eventData.hitEntity; // The entity that was damaged
        const damagingEntity = eventData.damagingEntity;

        // Log or handle the event
        if (damagingEntity.typeId == "cyd_mp:cute_iron_golem") {
            // apply impulse to entity hit

            // Direction and intensity of knockback
            const knockbackX = damagingEntity.location.x - damagedEntity.location.x; // X-axis direction
            const knockbackZ = damagingEntity.location.z - damagedEntity.location.z; // Z-axis direction

            // Normalize direction and apply intensity
            const intensity = 2.0; // Adjust intensity as needed
            const magnitude = Math.sqrt(knockbackX * knockbackX + knockbackZ * knockbackZ);
            const normalizedX = (knockbackX / magnitude) * intensity;
            const normalizedZ = (knockbackZ / magnitude) * intensity;

            damagedEntity.applyKnockback(normalizedX, 1.0, normalizedZ, 0.5);
        }
        if (damagingEntity.typeId == "cyd_mp:cute_hoglin") {
            // apply impulse to entity hit

            // Direction and intensity of knockback
            const knockbackX = damagingEntity.location.x - damagedEntity.location.x; // X-axis direction
            const knockbackZ = damagingEntity.location.z - damagedEntity.location.z; // Z-axis direction

            // Normalize direction and apply intensity
            const intensity = 1.0; // Adjust intensity as needed
            const magnitude = Math.sqrt(knockbackX * knockbackX + knockbackZ * knockbackZ);
            const normalizedX = (knockbackX / magnitude) * intensity;
            const normalizedZ = (knockbackZ / magnitude) * intensity;

            damagedEntity.applyKnockback(normalizedX, 2.0, normalizedZ, 0.5);
        }
    });
}

export function fearMechanic() {
    // map of entities that fear other entities
    let fearMap = {
        "cyd_mp:cute_creeper": ["minecraft:cat", "minecraft:ocelot"],
        "cyd_mp:cute_cave_spider": ["minecraft:armadillo"],
        "cyd_mp:cute_phantom": ["minecraft:cat", "minecraft:ocelot"],
        "cyd_mp:cute_piglin": ["minecraft:zombie_piglin", "minecraft:zoglin"],
        "cyd_mp:cute_spider": ["minecraft:armadillo"]
    }
    // get all entities
    let overworldFearingEntity = OVERWORLD.getEntities();
    let netherFearingEntity = NETHER.getEntities();
    let theEndFearingEntity = THE_END.getEntities();

    const fear = (entities) => {
        entities.forEach(nPEntity => {
            // pass entity to 
            let foundEntity = utilFunction.entityDetectNearbyEntities(nPEntity, 10);
            const isAfraid = fearMap[nPEntity.typeId] && fearMap[nPEntity.typeId].some(value => foundEntity.some(entity => value.includes(entity.typeId)));

            if (isAfraid) {
                if (utilFunction.isEntityHappy(nPEntity)) {
                    nPEntity.triggerEvent("evt:is_scared");
                    nPEntity.triggerEvent("evt:fear_mob");
                }
            }
        });
    };

    fear(overworldFearingEntity);
    fear(netherFearingEntity);
    fear(theEndFearingEntity);
}

export function tenPercentFear() {
    let overworld_pets = OVERWORLD.getEntities({
        families: ["pet"]
    });
    let nether_pets = NETHER.getEntities({
        families: ["pet"]
    });
    let the_end_pets = THE_END.getEntities({
        families: ["pet"]
    });

    const checkHealth = (entities) => {
        entities.forEach(nPEntity => {
            const healthComponent = nPEntity.getComponent(mc.EntityComponentTypes.Health);
            if (healthComponent) {
                const currentHealth = healthComponent.currentValue; // Get current health
                const maxHealth = healthComponent.effectiveMax; // Get maximum health

                if (currentHealth <= (maxHealth / 10)) {
                    if (utilFunction.isEntityHappy(nPEntity)) {
                        nPEntity.triggerEvent("evt:is_scared");
                        nPEntity.triggerEvent("evt:fear_health");
                    }
                }
            }
        });
    }
    checkHealth(overworld_pets);
    checkHealth(nether_pets);
    checkHealth(the_end_pets);
}



export function witherInitShieldTimer() {
    let overworld_wither = OVERWORLD.getEntities({
        type: "cyd_mp:cute_wither"
    });
    let nether_wither = NETHER.getEntities({
        type: "cyd_mp:cute_wither"
    });
    let the_end_wither = THE_END.getEntities({
        type: "cyd_mp:cute_wither"
    });


    const initTimer = (entities) => {
        entities.forEach(nPEntity => {
            let tameComponent = nPEntity.getComponent(mc.EntityComponentTypes.Tameable);
            if (tameComponent && tameComponent.isTamed) {
                let isTarget = nPEntity.getProperty("property:is_target");
                if (isTarget) {
                    let timeRemaining = nPEntity.getDynamicProperty("cyd_mp_shieldTimer");
                    if (!timeRemaining) {
                        let time = utilFunction.getRandomInt(5, 30);
                        nPEntity.setDynamicProperty("cyd_mp_shieldTimer", time);
                    }
                    if (timeRemaining && timeRemaining > 0) {
                        nPEntity.setDynamicProperty("cyd_mp_shieldTimer", timeRemaining - 1);
                    }
                    if (timeRemaining == 0) {
                        nPEntity.addEffect('resistance', 3 * 20, { amplifier: 255, showParticles: false });
                        nPEntity.triggerEvent("evt:shield_on");
                        nPEntity.setDynamicProperty("cyd_mp_shieldTimer", null);
                    }
                }
            }
        });
    }

    initTimer(overworld_wither);
    initTimer(nether_wither);
    initTimer(the_end_wither);
}