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

    CubeAttack1Damage,
    CubeAttack1Range,
    CubeAttack1KnockbackStrength,
    CubeAttack3Damage,
    CubeAttack3Range,
    CubeAttack3KnockbackStrength,

    CubeAttack4Damage,
    CubeAttack4Range,
    CubeAttack2Damage,
    CubeAttack2KnockbackStrength
} from './config';

system.afterEvents.scriptEventReceive.subscribe((event) => {
    const { sourceEntity: entity, id: eventId } = event;

    const attacks = {
        [`${namespace}:CubeAttack_1`]: attack1,
        [`${namespace}:CubeAttack_2`]: attack2,
        [`${namespace}:CubeAttack_3`]: attack3,
        [`${namespace}:CubeAttack_4`]: attack4
    };

    if (attacks[eventId]) {
        attacks[eventId](entity);
    }
});

function attack1(entity) {
    entity.triggerEvent("bunnystudios_rpg:attack_1");
    const entityDir = entity.getViewDirection();

    const executeAttack = (offset, delay) => {
        system.runTimeout(() => {
            if (!entity.isValid()) return;
            rotateCubeToNearestPlayer(entity);

            const targetLocation = {
                x: entity.location.x + entityDir.x * offset,
                y: entity.location.y,
                z: entity.location.z + entityDir.z * offset
            };
            const damage = entity.getProperty("bunnystudios_rpg:phase") === 2 ? CubeAttack1Damage * 2 : CubeAttack1Damage;

            entity.dimension.getEntities({
                location: targetLocation,
                excludeFamilies: ["inanimate"],
                excludeTypes: [entity.typeId, "item"],
                maxDistance: CubeAttack1Range
            }).forEach(target => {
                target.applyDamage(damage, {
                    cause: 'entityAttack',
                    damagingEntity: entity
                });
                target.applyKnockback(
                    entityDir.x,
                    entityDir.z,
                    CubeAttack1KnockbackStrength * 1.5,
                    CubeAttack1KnockbackStrength
                );
            });
        }, delay);
    };

    executeAttack(2, 14);
    executeAttack(6, 42);
}

function attack2(entity) {
    entity.triggerEvent("bunnystudios_rpg:attack_2");

    const hitBoxParams = {
        start: 0,
        width: 12,
        length: 8
    };

    system.runTimeout(() => {
        if (!entity.isValid()) return;
        rotateCubeToNearestPlayer(entity);
        const pos = entity.location;
        const angle = entity.getRotation().y * (Math.PI / 180);

        hitArea(entity, pos, hitBoxParams, angle);
    }, 32);
}

function hitArea(entity, pos, area, angle) {
    if (!entity.isValid()) return;

    const targets = entity.dimension.getEntities({
        location: pos,
        maxDistance: area.start + area.length,
        excludeTypes: [entity.typeId, "item"],
        excludeFamilies: ["inanimate"]
    });

    const sin = Math.sin(angle);
    const cos = Math.cos(angle);

    targets.forEach(target => {
        const dx = target.location.x - pos.x;
        const dz = target.location.z - pos.z;
        const distance = Math.sqrt(dx * dx + dz * dz);

        const rotX = dx * cos + dz * sin;
        const rotZ = -dx * sin + dz * cos;

        if (rotZ >= area.start &&
            rotZ <= area.start + area.length &&
            Math.abs(rotX) <= area.width / 2) {
            const damage = entity.getProperty("bunnystudios_rpg:phase") === 2 ? CubeAttack2Damage * 2 : CubeAttack2Damage;

            target.applyDamage(damage, {
                cause: 'entityAttack',
                damagingEntity: entity
            });

            target.applyKnockback(
                dx / distance,
                dz / distance,
                CubeAttack2KnockbackStrength * 1.5,
                CubeAttack2KnockbackStrength * 1
            );
        }
    });
}

function attack3(entity) {
    entity.triggerEvent("bunnystudios_rpg:attack_3");
    const entityDir = entity.getViewDirection();

    system.runTimeout(() => {
        if (!entity.isValid()) return;

        entity.dimension.getEntities({
            location: entity.location,
            excludeFamilies: ["inanimate"],
            excludeTypes: [entity.typeId, "item"],
            maxDistance: CubeAttack3Range
        }).forEach(target => {
            const damage = entity.getProperty("bunnystudios_rpg:phase") === 2 ? CubeAttack3Damage * 2 : CubeAttack3Damage;
            target.applyDamage(damage, {
                cause: 'entityAttack',
                damagingEntity: entity
            });
            target.applyKnockback(
                entityDir.x,
                entityDir.z,
                CubeAttack3KnockbackStrength * 1.5,
                CubeAttack3KnockbackStrength
            );
        });
    }, 42);
}

function attack4(entity) {
    entity.triggerEvent("bunnystudios_rpg:attack_4");

    const positions = [
        { x: -8, y: -6 }, { x: -6.5, y: -8 }, { x: -6.5, y: 0.5 }, { x: -4.5, y: 4 },
        { x: -4, y: -8 }, { x: -3.5, y: 6.5 }, { x: -0.5, y: -0.5 }, { x: 0.5, y: -5.5 },
        { x: 0.5, y: 5.5 }, { x: 1, y: -9 }, { x: 3.5, y: -7.5 }, { x: 4, y: 5 },
        { x: 4.5, y: 4 }, { x: 5, y: 1 }, { x: 7.5, y: 4 }
    ];

    const executeDamage = (delay) => {
        system.runTimeout(() => {
            if (!entity.isValid()) return;
            const damage = entity.getProperty("bunnystudios_rpg:phase") === 2 ? CubeAttack4Damage * 2 : CubeAttack4Damage;

            positions.forEach(pos => {
                entity.runCommandAsync(
                    `execute as @s at @s positioned ^${pos.x}^^${pos.y} run damage @e[type=!${namespace}:cube, type=!item, family=!inanimate, r=${CubeAttack4Range}] ${damage} entity_attack entity @s`
                );
            });
        }, delay);
    };

    executeDamage(33);
    executeDamage(43);
    executeDamage(53);
    executeDamage(63);
    executeDamage(73);
}


function rotateCubeToNearestPlayer(entity) {
    if (!entity.isValid()) return;

    const players = world.getAllPlayers().filter(player => player.getGameMode() === "survival" || player.getGameMode() === "adventure");
    if (!players.length) return;

    let nearestPlayer = players[0];
    let minDistance = Number.MAX_VALUE;

    for (const player of players) {
        const dx = player.location.x - entity.location.x;
        const dy = player.location.y - entity.location.y;
        const dz = player.location.z - entity.location.z;
        const distance = Math.sqrt(dx * dx + dy * dy + dz * dz);

        if (distance < minDistance) {
            minDistance = distance;
            nearestPlayer = player;
        }
    }

    const deltaX = nearestPlayer.location.x - entity.location.x;
    const deltaZ = nearestPlayer.location.z - entity.location.z;
    const yRot = -(Math.atan2(deltaX, deltaZ)) / Math.PI * 180;

    entity.setRotation({
        x: entity.getRotation().x,
        y: yRot
    });
}