import {
    EntityDamageCause,
    EntityHealthComponent,
    TicksPerSecond,
    system,
    world,
} from "@minecraft/server";
import { EntityObject, EntityRuntime } from "../global_api/EntityRuntime";
import { Vector3 } from "../global_api/Math";
import { BossEntity, BossLevel } from "./BossLevel";
import { Utils } from "./Utils";

const LEVEL_ONE_ATTACK_MERCIFUL_CUT = 1;
const LEVEL_ONE_ATTACK_NORMAL = 5;
const LEVEL_ONE_ATTACK_BLADE_FURY = 2;
const LEVEL_ONE_ATTACK_MEDITATION = 4;
const LEVEL_ONE_ATTACK_TELEPORT = 6;
const LEVEL_ONE_ATTACK_HURRICANE = 3;

const LEVEL_TWO_ATTACK_NORMAL = 1;
const LEVEL_TWO_ATTACK_ELETRIC_REDIRECTION = 2;
const LEVEL_TWO_ATTACK_THUNDER_FLOOR = 3;
const LEVEL_TWO_ATTACK_SHIELD = 4;
const LEVEL_TWO_ATTACK_WRATH = 5;

class BurazazuLevel extends BossLevel {
    /** @returns {Burazazu} */
    getObject() {
        return super.getObject();
    }
}

class BurazazuData {
    firstMeditation = false;
    transformTime = 0;
    level = 0;

    lastThunderShield = false;
}

class FirstLevel extends BurazazuLevel {
    mercifulCut = 0;
    bladeFury = 0;
    samuraiHurricane = 0;
    yingMeditation = 0;

    onAttackTick(type, tick) {
        super.onAttackTick(type, tick);
        if (type == LEVEL_ONE_ATTACK_MEDITATION) {
            const entity = this.getEntity();
            entity.clearVelocity();
            entity.addEffect("slowness", 4, { amplifier: 255, showParticles: false });
            entity.addEffect("resistance", 4, { amplifier: 255, showParticles: false });
            this.data.firstMeditation = true;
            if (tick == 20) {
                const health = this.getEntity().getComponent(EntityHealthComponent.componentId);
                health.setCurrentValue(Math.round(health.currentValue + health.effectiveMax * 0.1));
            }
            if (tick % 4 == 0) {
                entity.dimension.spawnParticle("pixell_bbo:force_field_1", entity.location);
                entity.dimension.spawnParticle("pixell_bbo:force_field_2", entity.location);
                entity.dimension.spawnParticle("pixell_bbo:force_field_3", entity.location);
            }
            if (tick % 5 == 0) {
                this.doWrathRain(1, true);
            }
        }
    }

    onRun() {
        super.onRun();
        const entity = this.getEntity();
        if (system.currentTick % (TicksPerSecond * 2) == 0 && false) {
            const velocity = Math.abs(entity.getVelocity().x) + Math.abs(entity.getVelocity().z);
            if (velocity > 0.2 && Math.random() < 0.1) {
                entity.applyImpulse({
                    x: entity.getVelocity().x * 4,
                    z: entity.getVelocity().z * 4,
                    y: -2,
                });
            }
        }
    }

    doHurricane() {
        this.debugAttack("Hurricane");
        this.setAttack(LEVEL_ONE_ATTACK_HURRICANE, 3.2);
        const entity = this.getEntity();
        const view = entity.getViewDirection();
        Utils.post(() => {
            Utils.featchViewEntities(this.getObject(), 10, 5, 4).forEach((e) => {
                if (e.entity?.typeId?.startsWith("minecraft:")) {
                    Utils.applyForce(e.entity, {
                        x: view.x * 3,
                        z: view.z * 3,
                        y: 1.0,
                    });
                    e.entity.addEffect("levitation", 20);
                    entity.dimension.spawnParticle(
                        "pixell_bbo:tornado_baruzazu",
                        e.entity.location
                    );
                    e.entity.applyDamage(4);
                }
            });
        }, 0.5);
    }

    onMeleeAttack() {
        const playersNext = this.getEntity().dimension.getEntities({
            location: this.getEntity().location,
            maxDistance: 3,
            type: "minecraft:player",
        });
        const playersMiddle = this.getEntity()
            .dimension.getEntities({
                location: this.getEntity().location,
                maxDistance: 8,
                type: "minecraft:player",
            })
            .filter((p) => {
                for (let player of playersNext) {
                    if (player.id == p.id) return false;
                }
                return true;
            });
        const playersLong = this.getEntity()
            .dimension.getEntities({
                location: this.getEntity().location,
                maxDistance: 64,
                type: "minecraft:player",
            })
            .filter((p) => {
                for (let player of playersNext) {
                    if (player.id == p.id) return false;
                }
                for (let player of playersMiddle) {
                    if (player.id == p.id) return false;
                }
                return true;
            });

        if (playersLong.length > 0) {
        }
        if (playersMiddle.length > 0) {
        }
        if (playersNext.length > 0) {
        }

        let rand = Math.round(Math.random() * 4);
        const health = this.getEntity().getComponent(EntityHealthComponent.componentId);

        if (
            health &&
            health.currentValue <= health.effectiveMax / 2 &&
            !this.data.firstMeditation
        ) {
            this.doYingMeditation();
        } else if (Math.random() > (playersLong.length > 0 ? 0.0 : 0.85)) {
            this.doTeleport();
        } else if (rand <= 1) {
            this.bladeFury = 0;
            this.doBladeFury();
        } else if (rand <= 2) {
            this.mercifulCut = 0;
            this.doMercifulCut();
        } else if (rand <= 3) {
            this.doHurricane();
        } else {
            this.doNormalAttack();
        }
    }

    doTeleport() {
        const players = this.getEntity().dimension.getPlayers({
            location: this.getEntity().location,
            maxDistance: 64,
        });
        if (players.length < 0) return;
        this.debugAttack("Teleport");

        this.setAttack(LEVEL_ONE_ATTACK_TELEPORT, 2.31);

        Utils.post(() => {
            const oldLocation = this.getEntity().location;

            this.getObject().__old_location = players[0].location;

            const blRay = players[0].dimension.getBlockFromRay(
                players[0].location,
                { x: 0, y: -1, z: 0 },
                { maxDistance: 20 }
            );

            if (blRay && blRay.block) {
                this.getObject().__old_location = blRay.block.above().location;
            }

            this.getEntity().teleport(players[0].location, {
                facingLocation: players[0].location,
            });

            this.getEntity().dimension.spawnParticle("pixell_bbo:bzz_teleport", oldLocation);

            this.getEntity().dimension.spawnParticle(
                "pixell_bbo:bzz_teleport",
                players[0].location
            );

            Utils.post(() => {
                players[0].dimension
                    .getEntities({
                        location: this.getEntity().location,
                        maxDistance: 3,
                    })
                    .forEach((e) => {
                        if (e.typeId.startsWith("minecraft:") && e.typeId != "minecraft:item") {
                            try {
                                Utils.applyForce(e, { x: 0, y: 1, z: 0 });
                                e.applyDamage(4);
                            } catch (e) {
                                // log("Bzz", e);
                            }
                        }
                    });
                try {
                    this.getEntity().applyDamage(1, {
                        damagingEntity: players[0],
                        cause: EntityDamageCause.entityAttack,
                    });
                } catch (e) {
                    // log("A", e);
                }
            }, 0.5);
            this.doWrathRain(1.0, true);
        }, 0.3);
    }

    onHealthChanged(newValue, oldValue) {
        this.mercifulCut++;
        this.bladeFury += Math.max(oldValue - newValue, 0);
        this.samuraiHurricane += Math.max(oldValue - newValue, 0);
        this.yingMeditation += Math.max(oldValue - newValue, 0);
    }

    doYingMeditation() {
        this.debugAttack("YingMeditation");
        this.setAttack(LEVEL_ONE_ATTACK_MEDITATION, 5.8);
    }

    doBladeFury() {
        this.debugAttack("Blade Fury");
        this.setAttack(LEVEL_ONE_ATTACK_BLADE_FURY, 3.2);
        const entity = this.getEntity();

        for (let t = 0; t < 3; t += 0.5) {
            Utils.post(() => {
                const view = entity.getViewDirection();
                entity.applyImpulse({
                    x: view.x * 2,
                    y: view.y * 2,
                    z: view.z * 2,
                });
                Utils.post(() => {
                    Utils.featchViewEntities(this.getObject(), 4, 4, 15).forEach((e) => {
                        if (e.entity.typeId.startsWith("minecraft:")) {
                            e.entity.applyDamage(5);
                            Utils.applyForce(e.entity, {
                                x: view.x * 2,
                                y: view.y * 1,
                                z: view.z * 2,
                            });
                        }
                    });
                }, 0.1);
            }, t);
        }
    }

    doWrathRain(delayedTime = 0.5) {
        const entity = this.getEntity();

        const players = entity.dimension.getEntities({
            type: "minecraft:player",
            maxDistance: 128,
            location: entity.location,
        });

        if (players.length == 0) return;

        const player = players[0];

        const location = player.location;

        entity.dimension.spawnParticle("pixell_bbo:thunder_explode", location);

        Utils.post(() => {
            for (let y = location.y + 40; y >= location.y; y -= 0.5) {
                entity.dimension.spawnParticle("pixell_bbo:thunderbolt_sz4", {
                    x: location.x + (Math.random() * 2 - 1),
                    z: location.z + (Math.random() * 2 - 1),
                    y,
                });

                entity.dimension.playSound("pixell_bbo.burazazu_d.thunder", location, {
                    sound: 0.5,
                    pitch: Math.random(),
                });
            }

            entity.dimension.getEntities({ location, maxDistance: 3 }).forEach((x) => {
                if (x.typeId.startsWith("minecraft:")) {
                    x.applyDamage(2);
                }
            });
        }, delayedTime);
    }

    doNormalAttack() {
        this.debugAttack("Normal");
        this.setAttack(LEVEL_ONE_ATTACK_NORMAL, 1);
        const view = this.getEntity().getViewDirection();
        Utils.post(() => {
            Utils.featchViewEntities(this.getObject(), 4, 2, 3).forEach((e) => {
                if (e.entity.typeId.startsWith("minecraft:")) {
                    Utils.applyForce(e.entity, {
                        x: view.x * 1,
                        y: 0.4,
                        z: view.z * 1,
                    });
                    e.entity.applyDamage(3);
                }
            });
        }, 0.75);
    }

    doMercifulCut() {
        this.debugAttack("MercifulCut");
        this.setAttack(LEVEL_ONE_ATTACK_MERCIFUL_CUT, 1.75);
        const entity = this.getEntity();
        const view = entity.getViewDirection();

        Utils.post(() => {
            Utils.featchViewEntities(this.getObject(), 12, 7, 7).forEach((e) => {
                e.entity.applyDamage(4);

                Utils.applyForce(e.entity, {
                    x: view.x * 3,
                    y: 0.4,
                    z: view.z * 3,
                });

                Utils.post(() => {
                    for (let y = -2; y <= 10; y += 3) {
                        for (let i = 0; i < 4; i++) {
                            entity.dimension.spawnParticle("pixell_bbo:thunderbolt_sz1", {
                                x: e.entity.location.x + Math.random() * -0.5 * 1.5,
                                y: e.entity.location.y + y,
                                z: e.entity.location.z + Math.random() * -0.5 * 1.5,
                            });
                        }
                        entity.dimension.playSound(
                            "ambient.weather.lightning.impact",
                            e.entity.location
                        );
                        e.entity.applyDamage(4);
                    }
                }, 0.1);
            });
        }, 1.0);
    }

    /** @returns {BurazazuData} **/ get data() {
        return super.data;
    }
}

class LastLevel extends BurazazuLevel {
    electroFloor = 0;
    thunderShield = 0;
    thunderRedirection = 0;
    wrath = 0;

    onMeleeAttack() {
        super.onMeleeAttack();
        // log("Burazazu", "Attack (LV2)");
        let randValue = Math.round(Math.random() * 5);
        if (this.thunderShield >= 50 && !this.data.lastThunderShield) {
            this.thunderShield = 0;
            this.doThunderShield();
        } else if (randValue <= 1) {
            this.doWrath();
        } else if (randValue <= 2) {
            this.thunderRedirection = false;
            this.doEletricRedirection();
        } else if (randValue <= 3) {
            this.electroFloor = 0;
            this.doEletricFloor();
        } else {
            this.doBasicAttack();
        }
    }

    doThunderShield() {
        this.debugAttack("ThunderShield");
        this.setAttack(LEVEL_TWO_ATTACK_SHIELD, 8);
    }

    onRangedAttack() {
        super.onRangedAttack();
        this.onMeleeAttack();
    }

    onAttackTick(type, tick) {
        super.onAttackTick(type, tick);
        const entity = this.getEntity();
        if (type == LEVEL_TWO_ATTACK_SHIELD) {
            this.data.lastThunderShield = true;
            entity.clearVelocity();
            entity.addEffect("slowness", 4, { amplifier: 255, showParticles: false });
            entity.addEffect("resistance", 4, { amplifier: 255, showParticles: false });
            entity.setProperty("pixell_bbo:shield", tick > 1);
            entity.addEffect("instant_health", 2, { amplifier: 2, showParticles: false });
            if (tick % 4 == 0) {
                entity.dimension.spawnParticle("pixell_bbo:force_field_1", entity.location);
                entity.dimension.spawnParticle("pixell_bbo:force_field_2", entity.location);
                entity.dimension.spawnParticle("pixell_bbo:force_field_3", entity.location);
            }
            if (tick % 5 == 0) {
                this.doWrathRain(1.0, true);
            }
        }
    }

    onRun() {
        super.onRun();
        this.getEntity().setProperty("pixell_bbo:shield", false);
    }

    onTick() {
        super.onTick();
        //const entity = this.getEntity();
        //entity.setOnFire(false);
        //entity.addEffect("fire_resistance", 4, { amplifier: 255, showParticles: false })
    }

    doWrathRain(delayedTime = 0.5, sound = false) {
        const entity = this.getEntity();

        const players = entity.dimension.getEntities({
            type: "minecraft:player",
            maxDistance: 128,
            location: entity.location,
        });

        if (players.length == 0) return;

        const player = players[0];

        const location = player.location;

        entity.dimension.spawnParticle("pixell_bbo:thunder_explode", location);

        Utils.post(() => {
            for (let y = location.y + 40; y >= location.y; y -= 0.5) {
                entity.dimension.spawnParticle("pixell_bbo:thunderbolt_sz4", {
                    x: location.x + (Math.random() * 2 - 1),
                    z: location.z + (Math.random() * 2 - 1),
                    y,
                });
            }

            if (sound) {
                entity.dimension.playSound("pixell_bbo.burazazu_d.thunder", location, {
                    pitch: Math.random() + 0.5,
                });
            }

            entity.dimension.getEntities({ location, maxDistance: 3 }).forEach((x) => {
                if (x.typeId.startsWith("minecraft:")) {
                    x.applyDamage(5);
                }
            });
        }, delayedTime);
    }

    doWrath() {
        this.debugAttack("Wrath");
        this.setAttack(LEVEL_TWO_ATTACK_WRATH, 5);
        const entity = this.getEntity();
        const timeOffset = 1.0;

        for (let i = 1; i <= 5; i++) {
            Utils.post(() => {
                this.doWrathRain();
            }, i * timeOffset);
        }
        Utils.post(() => {
            const view = entity.getViewDirection();
            entity.dimension
                .getEntities({
                    location: entity.location,
                    maxDistance: 13,
                })
                .forEach((e) => {
                    if (e?.typeId?.startsWith("minecraft:")) {
                        Utils.applyForce(e, {
                            x: view.x * 1,
                            y: view.y * 1,
                            z: view.z * 1,
                        });
                    }
                });
        }, 4.5);
    }

    doEletricRedirection() {
        const attackDamage = 5;

        const entity = this.getEntity();

        const players = entity.dimension.getEntities({
            type: "minecraft:player",
            location: entity.location,
            maxDistance: 25,
        });

        if (players.length == 0) return;

        this.setAttack(LEVEL_TWO_ATTACK_ELETRIC_REDIRECTION, 4);

        for (let i = 1; i < 4; i++) {
            Utils.post(() => {
                Utils.featchViewEntities(this.getObject(), 8, 8, 8).forEach((e) => {
                    if (e.entity?.typeId?.startsWith("minecraft:")) {
                        if (e.distance > 3) {
                            e.entity.applyDamage(attackDamage);
                        }
                        Utils.applyForce(e.entity, {
                            x: entity.getViewDirection().x * 3,
                            y: 0.2,
                            z: entity.getViewDirection().z * 3,
                        });
                    }
                });
            }, 0.75 * i);
        }
    }

    doEletricFloor() {
        this.debugAttack("ThunderFloor");
        this.setAttack(LEVEL_TWO_ATTACK_THUNDER_FLOOR, 3.7);
        const entity = this.getEntity();
        const off = () => Math.random() * 1 - 0.5;

        entity.dimension.spawnParticle(
            "pixell_bbo:eletric_area",
            new Vector3(0, 0.4, 0.0).add(entity.location)
        );

        for (let i = 1; i < 3; i += 0.5) {
            Utils.post(() => {
                const view = entity.getViewDirection();
                entity.dimension
                    .getEntities({
                        location: entity.location,
                        maxDistance: 12,
                    })
                    .forEach((e) => {
                        if (e?.typeId?.startsWith("minecraft:")) {
                            e.applyDamage(5);
                            Utils.applyForce(e, {
                                x: view.x * 1,
                                y: view.y * 1,
                                z: view.z * 1,
                            });
                            e.addEffect("mining_fatigue", TicksPerSecond * 2, {
                                showParticles: false,
                            });
                        }
                    });
            }, i);
        }
    }

    doBasicAttack() {
        const attackDamage = 4;
        this.debugAttack("BasicAttack");
        this.setAttack(LEVEL_TWO_ATTACK_NORMAL, 1.6);
        Utils.post(() => {
            const view = this.getEntity().getViewDirection();
            Utils.featchViewEntities(this.getObject(), 7, 6, 6).forEach((e) => {
                if (e.entity.typeId.startsWith("minecraft:")) {
                    e.entity.applyDamage(attackDamage);
                    Utils.applyForce(e.entity, {
                        x: view.x * 3,
                        z: view.z * 1,
                        y: view.y * 1,
                    });
                }
            });
        }, 0.5);
    }

    onHealthChanged(newValue, oldValue) {
        this.electroFloor++;
        this.thunderShield += Math.max(oldValue - newValue, 0);
        this.thunderRedirection += Math.max(oldValue - newValue, 0);
        this.wrath += Math.max(oldValue - newValue, 0);
    }

    /** @returns {BurazazuData} **/ get data() {
        return super.data;
    }
}

class Burazazu extends BossEntity {
    firstMode = new FirstLevel();
    lastMode = new LastLevel();

    onBegin() {
        Object.assign(this.data, new BurazazuData());
        super.onBegin();
    }

    onCreate() {
        super.onCreate();
        this.getEntity().setProperty("pixell_bbo:shield", false);
    }

    getComponentFor(level) {
        if (level == 0) {
            return this.firstMode;
        } else {
            return this.lastMode;
        }
    }

    /** @returns {Burazazu} */
    getObject() {
        return super.getObject();
    }

    onBeginTransform(toLevel) {
        super.onBeginTransform();
        if (toLevel > 1) return;

        const entity = this.getEntity();
        const circle = entity.dimension.spawnEntity("pixell_bbo:burazazu_circle", {
            x: entity.location.x,
            y: entity.location.y,
            z: entity.location.z,
        });
        circle.setDynamicProperty("target", entity.id);
    }

    getMeleeRange() {
        return this.getLevel() == 0 ? 4 : 10;
    }

    onAfterKill(tick) {
        super.onAfterKill(tick);
        // log("on after kill", tick);
        if (tick > TicksPerSecond * 6.2) {
            this.getEntity().remove();
        }
    }

    onTransforming(ticks) {
        super.onTransforming(ticks);
        //this.triggerEntityEvent("pixell_bbo:idle");
        this.setProperty("pixell_bbo:level_two", true);
        const entity = this.getEntity();
        const players = entity.dimension.getEntities({
            location: entity.location,
            maxDistance: 256,
            type: "mninecraft:player",
            closest: true,
        });

        if (players.length > 0) {
            entity.teleport(entity.location, {
                facingLocation: players[0].location,
            });
        }
    }

    isFixRotation() {
        return true;
    }

    onAttackTick(id, tick) {
        super.onAttackTick(id, tick);
        //log("AA", id, tick)
    }

    onEndTransform(level) {
        super.onEndTransform(level);

        this.triggerEntityEvent("pixell_bbo:level_two");

        this.triggerEntityEvent("pixell_bbo:move");
        system.runTimeout(() => {
            this.getEntity().runCommand("event entity @s pixell_bbo:move");
        }, TicksPerSecond);
    }

    getTransfromTime() {
        return TicksPerSecond * 5.5;
    }

    /** @returns {BurazazuData} **/ get data() {
        return super.data;
    }
}

class BurazazuCircle extends EntityObject {
    onBegin() {
        this.data.time = TicksPerSecond * 6.8;
    }

    onTick() {
        const entity = this.getEntity();
        const target = world.getEntity(this.data["target"]);

        if (!target) {
            entity.remove();

            return;
        }

        entity.teleport({
            x: target.location.x,
            y: target.location.y + 10,
            z: target.location.z,
        });

        if (this.data.time <= TicksPerSecond / 2) {
            entity.setProperty("pixell_bbo:hide", true);
        }
        if (this.data.time <= 0) {
            entity.remove();
            return;
        }

        this.data.time--;
    }
}

EntityRuntime.register("pixell_bbo:burazazu", Burazazu);
EntityRuntime.register("pixell_bbo:burazazu_circle", BurazazuCircle);
