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

import { executeRandomizedMove } from "../utils/utils";

const bosses = ["pixell_bbo:ares"];

function trackHealthStep(entity, stepSize, healthMap, callback) {
    const id = entity.id;

    const currentHealth = entity.getComponent("health").currentValue;

    if (!healthMap[id]) healthMap[id] = currentHealth;

    const lastHealth = healthMap[id];

    const lastStep = Math.floor(lastHealth / stepSize);

    const currentStep = Math.floor(currentHealth / stepSize);

    const stepsLost = lastStep - currentStep;

    if (stepsLost > 0) {
        callback(entity, stepsLost);
    }

    healthMap[id] = currentHealth;
}

world.afterEvents.projectileHitEntity.subscribe((event) => {
    const { source, projectile } = event;

    const entity = event.getEntityHit().entity;

    if (bosses.includes(entity.typeId)) {
        if (projectile.typeId.includes("arrow")) {
            if (entity.getProperty("self:stage") == 1) {
                entity.triggerEvent("self:dodge");

                system.runTimeout(() => {
                    entity.triggerEvent("self:dodge_remove");
                }, 0.5 * 20);
            }
        }
    }
});

const MeleeMoves = new Map([
    [
        "attack_combo",
        {
            weight: 10,
            duration: 2.0,
            properties: [
                {
                    name: "self:attacks",
                    value: "attack_combo",
                },
            ],
            event: "self:attack_combo",
            time_down_event: "self:attack_combo_remove",
        },
    ],
    [
        "spin",
        {
            weight: 10,
            duration: 1.5,
            properties: [
                {
                    name: "self:attacks",
                    value: "spin",
                },
            ],
            event: "self:spin",
            time_down_event: "self:spin_remove",
        },
    ],
    [
        "burial_supplicant",
        {
            weight: 8,
            duration: 2.0,
            properties: [
                {
                    name: "self:attacks",
                    value: "burial_supplicant",
                },
            ],
            event: "self:burial_supplicant",
            time_down_event: "self:burial_supplicant_remove",
        },
    ],
    [
        "wrath_warriors",
        {
            weight: 6,
            duration: 3.25,
            properties: [
                {
                    name: "self:attacks",
                    value: "wrath_warriors",
                },
            ],
            event: "self:wrath_warriors",
            time_down_event: "self:wrath_warriors_remove",
        },
    ],
]);

const RangedMoves = new Map([
    [
        "asteroid",
        {
            weight: 80,
            duration: 2,
            properties: [
                {
                    name: "self:attacks",
                    value: "asteroid",
                },
            ],
            event: "self:asteroid",
            time_down_event: "self:asteroid_remove",
        },
    ],
    [
        "flame_path",
        {
            weight: 40,
            duration: 4,
            properties: [
                {
                    name: "self:attacks",
                    value: "flame_path",
                },
            ],
            event: "self:flame_path",
            time_down_event: "self:flame_path_remove",
        },
    ],
    [
        "dragon_breath",
        {
            weight: 40,
            duration: 4,
            properties: [
                {
                    name: "self:attacks",
                    value: "dragon_breath",
                },
            ],
            event: "self:dragon_breath",
            time_down_event: "self:dragon_breath_remove",
        },
    ],
    [
        "axe",
        {
            weight: 10,
            duration: 4,
            properties: [
                {
                    name: "self:attacks",
                    value: "axe",
                },
            ],
            event: "self:axe",
            time_down_event: "self:axe_remove",
        },
    ],
    [
        "storm_blades",
        {
            weight: 20,
            duration: 2,
            properties: [
                {
                    name: "self:attacks",
                    value: "storm_blades",
                },
            ],
            event: "self:storm_blades",
            time_down_event: "self:storm_blades_remove",
        },
    ],
    [
        "pool_souls",
        {
            weight: 30,
            duration: 4,
            properties: [
                {
                    name: "self:attacks",
                    value: "pool_souls",
                },
            ],
            event: "self:pool_souls",
            time_down_event: "self:pool_souls_remove",
        },
    ],
]);

world.afterEvents.dataDrivenEntityTrigger.subscribe((event) => {
    try {
        const { entity, eventId } = event;

        if (bosses.includes(entity.typeId)) {
            let health = entity?.getComponent("health");

            if (eventId == "self:random_event") {
                executeRandomizedMove(entity, MeleeMoves);
            }

            if (eventId == "self:random_event_ranged_2") {
                executeRandomizedMove(entity, RangedMoves);
            }

            if (eventId == "self:wrath_warriors") {
                entity.addEffect("slowness", 1.5 * 20, {
                    amplifier: 255,
                    showParticles: false,
                });

                entity.addEffect("resistance", 3.5 * 20, {
                    amplifier: 1,
                    showParticles: false,
                });

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

                    const nearbyplayers = entity.dimension.getPlayers({
                        location: entity.location,
                        maxDistance: 16,
                    });

                    for (let player of nearbyplayers) {
                        player.dimension.spawnEntity("minecraft:lightning_bolt", player.location);

                        player.dimension.spawnParticle(
                            "pixell_bbo:red_thunder_bolt",
                            player.location
                        );

                        player.applyDamage(2, {
                            cause: EntityDamageCause.lightning,
                            damagingEntity: entity,
                        });
                    }
                }, 1.25 * 20);
            }

            if (eventId == "self:dying") {
                health.setCurrentValue(1);

                entity.addTag("pixell_bbo:dying");
            }

            if (eventId == "self:die") {
                system.runTimeout(() => {
                    entity?.triggerEvent("self:despawn");
                }, 6.24 * 20);
            }

            if (eventId == "self:second_form") {
                entity.removeTag("pixell_bbo:dying");

                entity.addEffect("instant_health", 5 * 20, {
                    amplifier: 1,
                    showParticles: false,
                });
            }

            if (eventId == "self:dash") {
                system.runTimeout(() => {
                    entity?.triggerEvent("self:dash_remove");
                }, 2 * 20);
            }

            if (eventId == "self:axe") {
                system.runTimeout(() => {
                    const block = entity.dimension.getBlock({
                        x: entity.location.x - entity.getViewDirection().x * 10,
                        y: entity.location.y + 1,
                        z: entity.location.z - entity.getViewDirection().z * 10,
                    });

                    if (block && block.isAir) {
                        entity.applyImpulse({
                            x: -entity.getViewDirection().x * 4,
                            y: 0.2,
                            z: -entity.getViewDirection().z * 4,
                        });
                    } else {
                        entity.applyImpulse({
                            x: entity.getViewDirection().x * 4,
                            y: 0.2,
                            z: entity.getViewDirection().z * 4,
                        });
                    }
                }, 1.45 * 20);

                system.waitTicks(4 * 20).then(() => {
                    entity?.triggerEvent("self:random_event_ranged_2");
                });
            }

            if (eventId == "self:burial_supplicant") {
                system.runTimeout(() => {
                    entity?.triggerEvent("self:burial_supplicant_remove");
                }, 0.75 * 20);

                const players = entity.dimension.getPlayers({
                    location: entity.location,
                    maxDistance: 10,
                });

                for (let player of players) {
                    system.runTimeout(() => {
                        player?.applyKnockback(0, 0, 0, 0.6);
                    }, 1.0 * 20);
                }
            }

            if (eventId == "self:berserk_transform") {
                system.runTimeout(() => {
                    entity?.triggerEvent("self:berserk_transform_remove");
                }, 1.0 * 20);
            }

            if (eventId == "self:asteroid") {
            }

            if (eventId == "self:storm_blades") {
            }

            if (eventId == "self:flame_path") {
                flamePath(entity, 4 * 20, 16);
            }

            if (eventId == "self:dragon_breath") {
                flamePath(entity, 4 * 20, 16);
            }

            if (eventId == "self:default") {
                system.runTimeout(() => {
                    entity?.triggerEvent("self:basic_attack");
                }, 2.8 * 20);
            }

            if (eventId == "self:attack_anim") {
                system.runTimeout(() => {
                    entity?.triggerEvent("self:attack_anim_remove");
                }, 0.25 * 20);
            }
        }
    } catch (error) {}
});

function flamePath(entity, duration, distance) {
    const runId = system.runInterval(() => {
        if (!entity) return;

        duration--;

        if (duration <= 0) {
            system.clearRun(runId);
            return;
        }

        const entities = entity?.getEntitiesFromViewDirection({ maxDistance: distance });

        for (let vEntity of entities) {
            vEntity.entity.applyDamage(1, {
                cause: EntityDamageCause.fire,
                damagingEntity: entity,
            });
            vEntity.entity.setOnFire(2);
        }
    });
}
