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

system.afterEvents.scriptEventReceive.subscribe(({ id, message, sourceEntity }) => {
    if (!sourceEntity) return;

    const args = message.split(" ").map(Number);
    const arg1 = !isNaN(args[0]) ? args[0] : 0;
    const arg2 = !isNaN(args[1]) ? args[1] : 0;

    const view = sourceEntity.getViewDirection();
    const pos = sourceEntity.location;
    const dim = sourceEntity.dimension;

    switch (id) {
        case "js:movement":
            sourceEntity.applyKnockback(view.x, view.z, arg1, arg2);
            break;

        case "js:damage": {
            const radius = arg2 > 0 ? arg2 : 3;
            const damage = arg1 > 0 ? arg1 : 1;

            try {
                const entities = dim.getEntities({
                    maxDistance: radius,
                    location: pos,
                    excludeTypes: [],
                });

                for (const e of entities) {
                    if (e.id === sourceEntity.id) continue;

                    e.applyDamage(damage, {
                        cause: EntityDamageCause.entityAttack,
                        damagingEntity: sourceEntity,
                    });
                }
            } catch (e) {
                console.warn("Error in js:damage:", e);
            }
            break;
        }
    }
});

const cloneCounters = new Map();
const telekinesisTargets = new Map();
const ABILITY_RADIUS = 8;
const FLOAT_DISTANCE = 3;
const THROW_FORCE = 4;

system.afterEvents.scriptEventReceive.subscribe((event) => {
    const player = event.sourceEntity;
    const playerName = player.nameTag;
    if (!player || player.typeId !== "minecraft:player") return;

    if (event.id === "yog:clone_despawn") {
        const allClones = player.dimension.getEntities({
            type: "yog:echo_clone",
        });

        for (const mob of allClones) {
            const tags = mob.getTags();
            const owned = tags.some(t => t.startsWith(`${playerName}_echo_`));
            if (owned) {
                mob.runCommandAsync("event entity @s despawn");
            }
        }
        cloneCounters.set(playerName, 0);
    }
    if (event.id === "yog:echo_ultimate_projectile_despawn") {
        const allClones = player.dimension.getEntities({
            type: "yog:echo_ultimate_projectile",
        });

        for (const mob of allClones) {
            const tags = mob.getTags();
            const owned = tags.some(t => t.startsWith(`${playerName}_echo_ultimate_`));
            if (owned) {
                mob.runCommandAsync("event entity @s despawn");
            }
        }
        cloneCounters.set(playerName, 0);
    }
    if (event.id === "yog:echo_skill1") {
        const allClones = player.dimension.getEntities({
            type: "yog:echo_clone",
        });

        for (const mob of allClones) {
            const tags = mob.getTags();
            const owned = tags.some(t => t.startsWith(`${playerName}_echo_`));
            if (owned) {
                mob.addTag("skill1");
            }
        }
    }
    if (event.id === "yog:echo_skill1_remove") {
        const allClones = player.dimension.getEntities({
            type: "yog:echo_clone",
        });

        for (const mob of allClones) {
            const tags = mob.getTags();
            const owned = tags.some(t => t.startsWith(`${playerName}_echo_`));
            if (owned && tags.includes("skill1")) {
                mob.removeTag("skill1");
            }
        }
    }
    if (event.id === "yog:infinity") {
        if (player && player.typeId === "minecraft:player") {
            const entities = player.dimension.getEntities({
                location: player.location,
                maxDistance: 4
            });

            for (const mob of entities) {
                if (mob.typeId === "minecraft:player" && mob.hasTag("alien_x")) continue;

                const dx = mob.location.x - player.location.x;
                const dz = mob.location.z - player.location.z;
                const length = Math.sqrt(dx * dx + dz * dz);

                if (length > 0.001) {
                    const push = 1 / length;

                    const targetX = mob.location.x + dx * push;
                    const targetY = mob.location.y;
                    const targetZ = mob.location.z + dz * push;

                    const block = player.dimension.getBlock({
                        x: Math.floor(targetX),
                        y: Math.floor(targetY),
                        z: Math.floor(targetZ)
                    });

                    if (block && !block.isAir) {
                        if (mob.typeId !== "yog:alien_x_domain" || mob.typeId !== "yog:alien_x_domain_mark") {
                            player.runCommandAsync(`scriptevent js:damage 9999999 4`);
                            mob.addEffect("slowness", 1, { amplifier: 255, showParticles: false });
                        }
                    } else {
                        if (mob.typeId !== "yog:alien_x_domain" || mob.typeId !== "yog:alien_x_domain_mark") {
                            mob.teleport(
                                { x: targetX, y: targetY, z: targetZ },
                                mob.dimension
                            );
                        }
                    }
                }
            }
        }
    }
    if (event.id === "yog:alien_x_transform") {
        let roll = Math.random();

        if (roll < 0.2) {
            system.run(() => {
                player.runCommandAsync("function systems/alien_x_transform");
            });
        } else {
            system.run(() => {
                player.runCommandAsync("function systems/failed_transform");
            });
        }
    }

    if (event.id === "yog:telekinesis.start") {
        const mobs = [...player.dimension.getEntities({
            location: player.location,
            maxDistance: ABILITY_RADIUS
        })];

        const filteredMobs = mobs.filter(mob =>
            mob.typeId !== "yog:alien_x_domain" &&
            mob.typeId !== "yog:alien_x_domain_mark" &&
            mob.typeId !== "yog:yog_avatar" &&
            !mob.hasTag("alien_x")
        );

        telekinesisTargets.set(player.id, filteredMobs);

        for (const mob of filteredMobs) {
            mob.addEffect("levitation", 20, { amplifier: 1, showParticles: false });
        }
    }
    if (event.id === "yog:telekinesis.hold") {
        const mobs = telekinesisTargets.get(player.id);
        if (!mobs) return;

        const viewDir = player.getViewDirection();
        const targetPos = {
            x: player.location.x + viewDir.x * FLOAT_DISTANCE,
            y: player.location.y + 1.5,
            z: player.location.z + viewDir.z * FLOAT_DISTANCE
        };

        for (const mob of [...mobs]) {
            if (!mob.isValid()) {
                mobs.splice(mobs.indexOf(mob), 1);
                continue;
            }

            mob.teleport(targetPos, { dimension: player.dimension, keepVelocity: false });
            mob.runCommandAsync(`execute as @s at @s run particle yog:sonic_wave5 ^^^`);
        }
    }
    if (event.id === "yog:telekinesis.release") {
        const mobs = telekinesisTargets.get(player.id);
        if (!mobs) return;

        const viewDir = player.getViewDirection();
        for (const mob of [...mobs]) {
            if (!mob.isValid()) continue;

            mob.applyImpulse({
                x: viewDir.x * THROW_FORCE,
                y: viewDir.y * THROW_FORCE + 1,
                z: viewDir.z * THROW_FORCE
            });
        }

        telekinesisTargets.delete(player.id);
    }

    if (event.id === "yog:airwalk") {
        let pos = player.location;
        let dimension = player.dimension;
        let belowBlock = dimension.getBlock({ x: pos.x, y: pos.y - 1, z: pos.z });

        if (!belowBlock || belowBlock.typeId === "minecraft:air") {
            player.addEffect("levitation", 1, { duration: 0.2, amplifier: 0.1, showParticles: false });
        }
    }
});

system.afterEvents.scriptEventReceive.subscribe((event) => {
    const entity = event.sourceEntity;
    if (!entity) return;

    if (entity.typeId === "yog:echo_clone" && event.id === "yog:echo_clone") {
        const mob = entity;

        const nearbyPlayers = mob.dimension.getEntities({
            type: "minecraft:player",
            closest: 1,
            location: mob.location,
        });

        if (nearbyPlayers.length === 0) return;
        const player = nearbyPlayers[0];
        const playerName = player.nameTag;

        if (!cloneCounters.has(playerName)) {
            cloneCounters.set(playerName, 0);
        }

        const tags = mob.getTags();
        const alreadyTagged = tags.some(t => t.includes("_echo_"));
        if (alreadyTagged) return;

        let count = cloneCounters.get(playerName) + 1;
        cloneCounters.set(playerName, count);

        const cloneName = `${playerName}_echo_${count}`;
        mob.nameTag = cloneName;
        mob.addTag(cloneName);
        mob.runCommandAsync(`tag @s add echo`);
    }

    if (entity.typeId === "yog:echo_ultimate_projectile" && event.id === "yog:echo_ultimate_projectile") {
        const mob = entity;

        const nearbyPlayers = mob.dimension.getEntities({
            type: "minecraft:player",
            closest: 1,
            location: mob.location,
        });

        if (nearbyPlayers.length === 0) return;
        const player = nearbyPlayers[0];
        const playerName = player.nameTag;

        if (!cloneCounters.has(playerName)) {
            cloneCounters.set(playerName, 0);
        }

        const tags = mob.getTags();
        const alreadyTagged = tags.some(t => t.includes("_echo_ultimate_"));
        if (alreadyTagged) return;

        let count = cloneCounters.get(playerName) + 1;
        cloneCounters.set(playerName, count);

        const cloneName = `${playerName}_echo_ultimate_${count}`;
        mob.nameTag = cloneName;
        mob.addTag(cloneName);
        mob.runCommandAsync(`tag @s add echo_ultimate`);
    }
});

world.afterEvents.entityDie.subscribe((event) => {
    const entity = event.deadEntity;
    if (entity.typeId === "yog:echo_clone") {
        const tags = entity.getTags();
        const tag = tags.find(t => t.includes("_echo_"));
        if (tag) {
            const playerName = tag.split("_echo_")[0];
            cloneCounters.set(playerName, 0);
        }
    }
});
