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

const SCREAM_EXCLUDE_FAMILIES = ["module", "door_close", "inanimate", "door_open", "door"];

const MORPHS = {
    "morph_pianosaurus:trigger": { property: "mebesm:is_morphed", hitboxEvent: "mebesm:apply_hitbox_pianosaurus", health: 30, damage: 4, screamItem: "mebesm:scream_morph_pianosaurus", removeItem: "mebesm:remove_morph_pianosaurus", screamAnimation: "animation.pianosauras.jumpscare", screamSound: "mob.pianosauras.scream", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_pianosaurus" },
    "morph_bunzo_bunny:trigger": { property: "mebesm:is_morphed_bunzo_bunny", hitboxEvent: "mebesm:apply_hitbox_bunzo_bunny", health: 30, damage: 4, screamItem: "mebesm:scream_morph_bunzo_bunny", removeItem: "mebesm:remove_morph_bunzo_bunny", screamAnimation: "animation.besmc_lever.scream", screamSound: "BunnyScream", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_bunzo_bunny" },
    "morph_chum_chomlkins:trigger": { property: "mebesm:is_morphed_chum_chomlkins", hitboxEvent: "mebesm:apply_hitbox_chum_chomlkins", health: 30, damage: 4, screamItem: "mebesm:scream_morph_chum_chomlkins", removeItem: "mebesm:remove_morph_chum_chomlkins", screamAnimation: "animation.chum_chomlkins.scream", screamSound: "chum_chomlkins_scream", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_chum_chomlkins" },
    "morph_giblet:trigger": { property: "mebesm:is_morphed_giblet", hitboxEvent: "mebesm:apply_hitbox_giblet", health: 20, damage: 4, removeItem: "mebesm:remove_morph_giblet", returnItem: "mebesm:morph_giblet" },
    "morph_pj_pug_a_pillar:trigger": { property: "mebesm:is_morphed_pj_pug_a_pillar", hitboxEvent: "mebesm:apply_hitbox_pj_pug_a_pillar", health: 30, damage: 4, screamItem: "mebesm:scream_morph_pj_pug_a_pillar", removeItem: "mebesm:remove_morph_pj_pug_a_pillar", screamAnimation: "animation.pj_pug_a_pillar.scream", screamSound: "pj_attack", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_pj_pug_a_pillar" },
    "morph_yarnaby:trigger": { property: "mebesm:is_morphed_yarnaby", hitboxEvent: "mebesm:apply_hitbox_yarnaby", health: 30, damage: 4, screamItem: "mebesm:scream_morph_yarnaby", removeItem: "mebesm:remove_morph_yarnaby", screamAnimation: "animation.besmc_yarnaby.scream", screamSound: "mob.besmc_yarnaby.throw", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_yarnaby" },
    "morph_nightmare_huggy:trigger": { property: "mebesm:is_morphed_nightmare_huggy", hitboxEvent: "mebesm:apply_hitbox_nightmare_huggy", health: 30, damage: 4, screamItem: "mebesm:scream_morph_nightmare_huggy", removeItem: "mebesm:remove_morph_nightmare_huggy", screamAnimation: "animation.besmc_nightmare_huggy.scream", screamSound: "nightmare_huggy.scream", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_nightmare_huggy" },
    "morph_prototype:trigger": { property: "mebesm:is_morphed_prototype", hitboxEvent: "mebesm:apply_hitbox_prototype", health: 30, damage: 4, screamItem: "mebesm:scream_morph_prototype", removeItem: "mebesm:remove_morph_prototype", screamAnimation: "animation.prototype.scream", screamSound: "PrototypeScream", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_prototype" },
    "morph_lily_lovebraids:trigger": { property: "mebesm:is_morphed_lily", hitboxEvent: "mebesm:apply_hitbox_lily_lovebraids", health: 30, damage: 4, screamItem: "mebesm:scream_morph_lily_lovebraids", removeItem: "mebesm:remove_morph_lily_lovebraids", screamAnimation: "animation.lily_lovebraids.scream", screamSound: "lily_lovebraids_scream", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_lily_lovebraids" },
    "morph_poppy:trigger": { property: "mebesm:is_morphed_poppy", hitboxEvent: "mebesm:apply_hitbox_poppy", health: 20, damage: 4, removeItem: "mebesm:remove_morph_poppy", returnItem: "mebesm:morph_poppy" },
    "morph_dogday:trigger": { property: "mebesm:is_morphed_dogday", hitboxEvent: "mebesm:apply_hitbox_dogday", health: 30, damage: 4, screamItem: "mebesm:scream_morph_dogday", removeItem: "mebesm:remove_morph_dogday", screamAnimation: "animation.besmc_handprint_crate.scream", screamSound: "dogdaythrow", screamRadius: 8, screamDamage: 20, returnItem: "mebesm:morph_dogday" },
    "morph_huggy_wuggy:trigger": { property: "mebesm:is_morphed_huggy_wuggy", hitboxEvent: "mebesm:apply_hitbox_huggy_wuggy", health: 40, damage: 6, screamItem: "mebesm:scream_morph_huggy_wuggy", removeItem: "mebesm:kill_morph_huggy_wuggy", screamAnimation: "animation.huggy_wuggy.scream", screamSound: "huggy_scream", screamRadius: 10, screamDamage: 25, returnItem: "mebesm:morph_huggy_wuggy" },
    "morph_kissy_missy:trigger": { property: "mebesm:is_morphed_kissy_missy", hitboxEvent: "mebesm:apply_hitbox_huggy_wuggy", health: 40, damage: 6, screamItem: "mebesm:scream_morph_kissy_missy", removeItem: "mebesm:kill_morph_kissy_missy", screamAnimation: "animation.kissy_missy.scream", screamSound: "huggy_scream", screamRadius: 10, screamDamage: 25, returnItem: "mebesm:morph_kissy_missy" },
};

function isAnyMorphActive(player) {
    for (const cfg of Object.values(MORPHS)) {
        if (player.getProperty(cfg.property)) return true;
    }
    return player.getProperty("mebesm:is_morphed_huggy_wuggy_wounded") || player.getProperty("mebesm:is_morphed_kissy_missy_wounded");
}

function doScream(player, cfg, screamItemId) {
    try { player.playAnimation(cfg.screamAnimation); } catch { }
    try { player.playSound(cfg.screamSound); } catch { }

    const nearbyEntities = player.dimension.getEntities({
        location: player.location,
        maxDistance: cfg.screamRadius,
        excludeFamilies: SCREAM_EXCLUDE_FAMILIES,
        excludeTypes: ["minecraft:player"],
    });
    for (const entity of nearbyEntities) {
        try {
            entity.teleport(
                { x: player.location.x, y: player.location.y, z: player.location.z },
                { dimension: player.dimension }
            );
            entity.applyDamage(cfg.screamDamage, { cause: "entityAttack", damagingEntity: player });
        } catch { }
    }

    if (screamItemId) {
        const inv = player.getComponent("minecraft:inventory").container;
        inv.setItem(player.selectedSlotIndex);
        player.runCommand(`give @s ${screamItemId} 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
    }
}

function removeMorphFull(player, returnItemId) {
    const inv = player.getComponent("minecraft:inventory").container;

    for (const cfg of Object.values(MORPHS)) {
        player.setProperty(cfg.property, false);
    }
    player.setProperty("mebesm:is_morphed_huggy_wuggy_wounded", false);
    player.setProperty("mebesm:is_morphed_kissy_missy_wounded", false);
    player.setProperty("mebesm:huggy_is_statue", false);

    player.runCommand("effect @s health_boost 1 0 true");
    player.triggerEvent("mebesm:reset_hitbox");

    const morphItemPrefixes = ["mebesm:kill_morph", "mebesm:remove_morph", "mebesm:scream_morph",
        "mebesm:statue_morph", "mebesm:remove_statue", "mebesm:morph_huggy_wuggy_wounded",
        "mebesm:morph_kissy_missy_wounded", "mebesm:worn_morph_prototype"];
    for (let i = 0; i < inv.size; i++) {
        const item = inv.getItem(i);
        if (item && morphItemPrefixes.some(p => item.typeId.startsWith(p))) {
            inv.setItem(i);
        }
    }
    inv.addItem(new ItemStack(returnItemId, 1));
}

world.afterEvents.playerSpawn.subscribe((ev) => {
    const { player, initialSpawn } = ev;
    if (!initialSpawn) return;
    system.runTimeout(() => {
        for (const cfg of Object.values(MORPHS)) {
            if (player.getProperty(cfg.property) || player.getProperty("mebesm:is_morphed_huggy_wuggy_wounded") || player.getProperty("mebesm:is_morphed_kissy_missy_wounded")) {
                player.triggerEvent(cfg.hitboxEvent);
                break;
            }
        }
    }, 20);
});

system.runInterval(() => {
    for (const player of world.getAllPlayers()) {
        const move = player.getComponent("minecraft:movement");
        if (player.getProperty("mebesm:huggy_is_statue")) {
            if (move) move.setCurrentValue(0);
        } else {
            if (move && move.currentValue === 0) move.resetToDefaultValue();
        }
    }
}, 2);

world.afterEvents.entityHitEntity.subscribe((ev) => {
    const attacker = ev.damagingEntity;
    if (attacker?.typeId !== "minecraft:player") return;
    for (const cfg of Object.values(MORPHS)) {
        if (attacker.getProperty(cfg.property)) {
            ev.hitEntity.applyDamage(cfg.damage, { damagingEntity: attacker });
            break;
        }
    }
});

world.beforeEvents.worldInitialize.subscribe((ev) => {
    const reg = ev.itemComponentRegistry;

    for (const [component, cfg] of Object.entries(MORPHS)) {
        reg.registerCustomComponent(component, {
            onUse(event) {
                const player = event.source;
                if (isAnyMorphActive(player)) return;

                const inv = player.getComponent("minecraft:inventory").container;
                player.setProperty(cfg.property, true);

                const amplifier = Math.max(0, Math.ceil((cfg.health - 20) / 4) - 1);
                player.addEffect("health_boost", 999999, { amplifier, showParticles: false });

                system.run(() => {
                    const health = player.getComponent("minecraft:health");
                    health.setCurrentValue(health.effectiveMax);
                    player.triggerEvent(cfg.hitboxEvent);
                });

                inv.setItem(player.selectedSlotIndex);
                player.runCommand(`give @s ${cfg.removeItem} 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
                if (cfg.screamItem) player.runCommand(`give @s ${cfg.screamItem} 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);

                if (cfg.property === "mebesm:is_morphed_huggy_wuggy") {
                    player.runCommand(`give @s mebesm:statue_morph_huggy_wuggy 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
                    player.runCommand(`give @s mebesm:morph_huggy_wuggy_wounded 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
                }
                if (cfg.property === "mebesm:is_morphed_kissy_missy") {
                    player.runCommand(`give @s mebesm:morph_kissy_missy_wounded 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
                }
            }
        });

        if (cfg.screamItem) {
            const screamComponentName = cfg.screamItem.replace("mebesm:", "") + ":trigger";
            reg.registerCustomComponent(screamComponentName, {
                onUse(event) {
                    const player = event.source;
                    if (!player.getProperty(cfg.property)) {
                        const isWoundedHuggy = cfg.property === "mebesm:is_morphed_huggy_wuggy" &&
                            player.getProperty("mebesm:is_morphed_huggy_wuggy_wounded");
                        const isWoundedKissy = cfg.property === "mebesm:is_morphed_kissy_missy" &&
                            player.getProperty("mebesm:is_morphed_kissy_missy_wounded");
                        if (!isWoundedHuggy && !isWoundedKissy) return;
                    }
                    doScream(player, cfg, cfg.screamItem);
                }
            });
        }

        reg.registerCustomComponent(`${cfg.removeItem.replace("mebesm:", "")}:trigger`, {
            onUse(event) {
                const player = event.source;
                const inv = player.getComponent("minecraft:inventory").container;

                player.setProperty(cfg.property, false);
                player.setProperty("mebesm:is_morphed_huggy_wuggy_wounded", false);
                player.setProperty("mebesm:is_morphed_kissy_missy_wounded", false);
                player.setProperty("mebesm:huggy_is_statue", false);

                player.runCommand("effect @s health_boost 1 0 true");
                player.triggerEvent("mebesm:reset_hitbox");

                const toRemove = [cfg.screamItem, cfg.removeItem, "mebesm:statue_morph_huggy_wuggy", "mebesm:remove_statue_morph_huggy_wuggy", "mebesm:morph_huggy_wuggy_wounded", "mebesm:morph_kissy_missy_wounded"];
                for (let i = 0; i < inv.size; i++) {
                    const item = inv.getItem(i);
                    if (item && toRemove.includes(item.typeId)) inv.setItem(i);
                }
                inv.addItem(new ItemStack(cfg.returnItem, 1));
            }
        });
    }

    reg.registerCustomComponent("morph_huggy_wuggy_wounded:trigger", {
        onUse(e) {
            const p = e.source;
            const isWounded = p.getProperty("mebesm:is_morphed_huggy_wuggy_wounded");
            p.setProperty("mebesm:is_morphed_huggy_wuggy_wounded", !isWounded);
            p.setProperty("mebesm:is_morphed_huggy_wuggy", isWounded);
            p.triggerEvent("mebesm:apply_hitbox_huggy_wuggy");
        }
    });

    reg.registerCustomComponent("morph_kissy_missy_wounded:trigger", {
        onUse(e) {
            const p = e.source;
            const isWounded = p.getProperty("mebesm:is_morphed_kissy_missy_wounded");
            p.setProperty("mebesm:is_morphed_kissy_missy_wounded", !isWounded);
            p.setProperty("mebesm:is_morphed_kissy_missy", isWounded);
            p.triggerEvent("mebesm:apply_hitbox_huggy_wuggy");
        }
    });

    reg.registerCustomComponent("scream_morph_huggy_wuggy_wounded:trigger", {
        onUse(e) {
            const p = e.source;
            if (!p.getProperty("mebesm:is_morphed_huggy_wuggy_wounded")) return;
            doScream(p, MORPHS["morph_huggy_wuggy:trigger"], "mebesm:scream_morph_huggy_wuggy");
        }
    });

    reg.registerCustomComponent("scream_morph_kissy_missy_wounded:trigger", {
        onUse(e) {
            const p = e.source;
            if (!p.getProperty("mebesm:is_morphed_kissy_missy_wounded")) return;
            doScream(p, MORPHS["morph_kissy_missy:trigger"], "mebesm:scream_morph_kissy_missy");
        }
    });

    reg.registerCustomComponent("kill_morph_huggy_wuggy_wounded:trigger", {
        onUse(e) {
            removeMorphFull(e.source, "mebesm:morph_huggy_wuggy");
        }
    });

    reg.registerCustomComponent("kill_morph_kissy_missy_wounded:trigger", {
        onUse(e) {
            removeMorphFull(e.source, "mebesm:morph_kissy_missy");
        }
    });

    reg.registerCustomComponent("worn_morph_prototype:trigger", {
        onUse(e) {
            const p = e.source;
            if (p.getProperty("mebesm:is_morphed_prototype")) {
                p.triggerEvent("mebesm:apply_hitbox_prototype");
            }
        }
    });

    reg.registerCustomComponent("statue_morph_huggy_wuggy:trigger", {
        onUse(e) {
            const p = e.source;
            p.setProperty("mebesm:huggy_is_statue", true);
            const inv = p.getComponent("minecraft:inventory").container;
            inv.setItem(p.selectedSlotIndex);
            p.runCommand(`give @s mebesm:remove_statue_morph_huggy_wuggy 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
        }
    });

    reg.registerCustomComponent("remove_statue_morph_huggy_wuggy:trigger", {
        onUse(e) {
            const p = e.source;
            p.setProperty("mebesm:huggy_is_statue", false);
            const inv = p.getComponent("minecraft:inventory").container;
            inv.setItem(p.selectedSlotIndex);
            p.runCommand(`give @s mebesm:statue_morph_huggy_wuggy 1 0 {"item_lock":{"mode":"lock_in_inventory"}}`);
        }
    });
});