import * as mc from "@minecraft/server";
import * as effects from "../effects";
import * as entityUtils from "../utils/entityUtils";
import * as selectors from "../utils/selectors";
import * as vector from "../utils/vector";

const ATTACK_SLAM_DAMAGE = 34;
const ATTACK_SWING_DAMAGE = 30;

export function eventBehavior(event) {
    const entity = event.entity;
    //mc.world.sendMessage(entity.typeId+':    '+event.eventId+'');
    if (event.eventId === "minecraft:entity_spawned") {
        entity.setProperty('hf_mzs:y_rot', entity.getRotation().y);
        return;
    }
    if (event.eventId === "register" && !entity.getProperty("hf_mzs:sleeping") && !entity.getProperty("hf_mzs:awaking")) {
        entity.triggerEvent("attack_res");
        entity.setDynamicProperty('hf_mzs:ding_cooldown', 0);
        entity.setDynamicProperty('hf_mzs:should_face_player', false);
        return;
    }
    if (event.eventId === 'step') {
        entity.removeEffect("slowness");
        entity.addEffect("slowness", 7, {
            amplifier: 2,
            showParticles: false
        });
        return;
    }

    if (event.eventId === 'awaken2') {
        rotateToTarget(entity);
        return;
    }

    if (event.eventId === 'attack_stomp_2') {
        const entities = selectors.union({
            location: entity.location,
            maxDistance: 7,
        }, ["player", "mob"], entity.dimension, entity.id);
        entity.triggerEvent("cooldown_stomp");
        entity.runCommand("/camerashake add @a[r=16] 0.5 0.9 positional")

        for (var i = 0; i < entities.length; i++) {
            if (entities[i] === undefined || !entities[i].isOnGround)
                continue;
            const r = vector.flatten(vector.subtract(entities[i].location, entity.location), 'y')
            entities[i].applyKnockback(r.x, r.z, 0.5, 1.7);
            entities[i].applyDamage(Math.floor(7 / vector.magnitude(vector.subtract(entity.location, entities[i].location))), {
                cause: "entityAttack",
                damagingEntity: entity
            });
        }

        // block knockup effect
        const offset = {
            x: 0.4,
            y: 1,
            z: 0
        }
        for (let i = 0; i < 20; i++) {
            const count = (i >= 10) ? 20 - i : i;
            //mc.world.sendMessage(`${count}`)
            for (let j = 0; j < count * 2; j++) {
                if (Math.random() <= 0.5)
                    continue;
                const loc = {
                    x: entity.location.x - 10 + i,
                    y: entity.location.y - 1,
                    z: entity.location.z - count + j
                };
                const dist = vector.magnitude(vector.subtract(entity.location, vector.add(loc, offset)));
                if (dist <= 2)
                    continue;
                //mc.world.sendMessage(`${vector.string(loc)}}`)
                if (entity.dimension.getBlock(vector.add(loc, vector.up)).typeId !== "minecraft:air")
                    continue;
                const block = entity.dimension.getBlock(loc);
                if (block === undefined)
                    continue;
                if (block.typeId === "minecraft:cobblestone") {
                    const e = entity.dimension.spawnEntity("hf_mzs:block_projectile", vector.add(loc, offset))
                    e.setProperty("hf_mzs:variant", 0);
                    e.setProperty("hf_mzs:dist", dist);
                    continue;
                }
                if (block.typeId === "minecraft:smooth_stone") {
                    const e = entity.dimension.spawnEntity("hf_mzs:block_projectile", vector.add(loc, offset))
                    e.setProperty("hf_mzs:variant", 1);
                    e.setProperty("hf_mzs:dist", dist);
                    continue;
                }
                if (block.typeId === "minecraft:chiseled_stone_bricks") {
                    const e = entity.dimension.spawnEntity("hf_mzs:block_projectile", vector.add(loc, offset))
                    e.setProperty("hf_mzs:variant", 2);
                    e.setProperty("hf_mzs:dist", dist);
                    continue;
                }
            }
        }
        dustEffect(entity);
        return;
    }

    // begin tracking the player before first swing for 20 ticks
    if (event.eventId === 'attack_swing1' || event.eventId === 'attack_swing2' || event.eventId === 'attack_swing3') {
        entity.setDynamicProperty('hf_mzs:should_face_player', true);
        mc.system.runTimeout(()=>{
            entity.setDynamicProperty('hf_mzs:should_face_player', false);
        }, 20);
    }
    // begin tracking the player before 2nd swing for 7 ticks
    if (event.eventId === 'attack_swing2_2' || event.eventId === 'attack_swing3_2') {
        mc.system.runTimeout(()=>{
            entity.setDynamicProperty('hf_mzs:should_face_player', true);
            mc.system.runTimeout(()=>{
                entity.setDynamicProperty('hf_mzs:should_face_player', false);
            }, 7);
        }, 22-7);
    }
    // begin tracking the player before spin for 20 ticks, also slide him forward
    if (event.eventId === 'attack_swing3_3') {
        mc.system.runTimeout(()=>{
            entity.setDynamicProperty('hf_mzs:should_face_player', true);
            mc.system.runTimeout(()=>{
                entity.applyImpulse(vector.flatten(entity.getViewDirection(), 'y'))
                entity.setDynamicProperty('hf_mzs:should_face_player', false);
            }, 20);
        }, 27-20);
    }

    if (event.eventId === 'attack_swing1_2' || event.eventId === 'attack_swing2_2' || event.eventId === 'attack_swing3_2') {
        entity.setProperty('hf_mzs:slam_counter', entity.getProperty('hf_mzs:slam_counter') + 1);
    }
    if (event.eventId === 'attack_swing1_2' || event.eventId === 'attack_swing2_2' || event.eventId === 'attack_swing2_3' || event.eventId === 'attack_swing3_2' || event.eventId === 'attack_swing3_3') {
        //mc.world.sendMessage(`Attack angle 2: ${entity.getProperty('hf_mzs:y_rot')}`);
        const arc = selectors.getEntitiesArc(entity, ["player", "mob"], 5, 100, false, entity.getProperty('hf_mzs:y_rot'));
        const r = entity.getViewDirection();

        for (var i = 0; i < arc.length; i++) {
            if (arc[i] === undefined)
                continue;
            if (entityUtils.breakShield(arc[i]))
                continue;
            arc[i].applyKnockback(r.x, r.z, 2.5, 0.1);
            arc[i].applyDamage(ATTACK_SWING_DAMAGE, {
                cause: "entityAttack",
                damagingEntity: entity
            });
        }
        return;
    }
    if (event.eventId === 'attack_swing3_4') {
        //mc.world.sendMessage("swing3");
        const entities = selectors.union({
            location: entity.location,
            maxDistance: 5,
        }, ["player", "mob"], entity.dimension, entity.id);
        const r = entity.getViewDirection();

        for (var i = 0; i < entities.length; i++) {
            //mc.world.sendMessage("swing_i");
            if (entities[i] === undefined)
                continue;
            if (entityUtils.breakShield(entities[i]))
                continue;
            entities[i].applyKnockback(r.x, r.z, 1.4, 0.2);
            entities[i].applyDamage(ATTACK_SWING_DAMAGE, {
                cause: "entityAttack",
                damagingEntity: entity
            });
        }
        return;
    }
    // begin tracking the player before slam for 21 ticks
    if (event.eventId === 'attack_slam') {
        entity.setDynamicProperty('hf_mzs:should_face_player', true);
        mc.system.runTimeout(()=>{
            entity.setDynamicProperty('hf_mzs:should_face_player', false);
        }, 21);
    }
    if (event.eventId === 'attack_slam_2') {
        //mc.world.sendMessage(`Attack angle 2: ${entity.getProperty('hf_mzs:y_rot')}`);
        const arc = selectors.getEntitiesArc(entity, ["player", "mob"], 5, 40, false, entity.getProperty('hf_mzs:y_rot'));
        const r = entity.getViewDirection();
        entity.runCommand("/camerashake add @a[r=16] 0.5 0.9 positional")
        dustEffect(entity);

        for (var i = 0; i < arc.length; i++) {
            if (arc[i] === undefined)
                continue;
            if (entityUtils.breakShield(arc[i]))
                continue;
            arc[i].applyKnockback(r.x, r.z, 2.5, 0.1);
            arc[i].applyDamage(ATTACK_SLAM_DAMAGE, {
                cause: "entityAttack",
                damagingEntity: entity
            });
        }
        return;
    }
    // make it despawn because very rarely it fails to for some reason
    if (event.eventId === 'death') {
        mc.system.runTimeout(()=>{
            if (!event.entity.isValid())
                return;
            event.entity.triggerEvent("drop");
        }, 95);
        return;
    }
}
export function tick20(entity) {
    if (entity.getProperty("hf_mzs:sleeping"))
        checkForPlayer(entity);
    if (entity.getProperty('hf_mzs:cooldown_stomp') > 0)
        entity.setProperty('hf_mzs:cooldown_stomp', entity.getProperty('hf_mzs:cooldown_stomp') - 1)
}
export function tick5(entity) {
    if (entity.getProperty('hf_mzs:hurt_state') === 'vulnerable') {
        entity.runCommand("/execute as @s at @s rotated ~ 0 positioned ^^^-10 if entity @p[r=10.5] run event entity @s player_behind");
        entity.runCommand("/execute as @s at @s rotated ~ 0 positioned ^^^-10 unless entity @p[r=10.5] run event entity @s no_player_behind");
        /*
        const arc = selectors.getEntitiesArc(entity, ["player"], 5.5, 100, true, entity.getProperty('hf_mzs:y_rot'));
        if (arc[0] !== undefined) {
            entity.triggerEvent("player_behind");
            //mc.world.sendMessage("behind");
        }
        else {
            entity.triggerEvent("no_player_behind");
            //mc.world.sendMessage("not behind");
        }
        */
    }
}
export function tick1(entity) {
    //entity.runCommand("/fill ~-2~~-2 ~2~2~2 hf_mzs:water_replacer_dummy [] replace flowing_water")
    //entity.runCommand("/fill ~-2~~-2 ~2~2~2 hf_mzs:water_replacer_dummy [] replace water")
    //mc.world.sendMessage(`${entity.getProperty('hf_mzs:sleeping')}    ${entity.getProperty('hf_mzs:awaking')}`);
    if (entity.getDynamicProperty('hf_mzs:should_face_player')) {
        rotateToTarget(entity);
    }

    if (entity.getProperty('hf_mzs:sleeping') || entity.getProperty('hf_mzs:awaking') || 
        (entity.getProperty('hf_mzs:attack_mode') !== 'none' && entity.getProperty('hf_mzs:attack_mode') !== 'stomp')) 
    {
        //mc.world.sendMessage(`${entity.getProperty('hf_mzs:y_rot')}      ${entity.getRotation().y}`);
        entity.setRotation({ x: 0, y: entity.getProperty('hf_mzs:y_rot') });
    }

    // push entities away
    const entities = selectors.union({
        location: entity.location,
        maxDistance: 1.5,
        excludeFamilies: [ "inanimate" ]
    }, ["player", "mob"], entity.dimension, entity.id);
    for (let i = 0; i < entities.length; i++) {
        if (entities[i] === undefined)
            continue;
        const v = vector.flatten(vector.subtract(entities[i].location, entity.location), 'y');
        entities[i].applyKnockback(v.x, v.y, 1, 0.1);
    }
}

function checkForPlayer(entity) {
    const players = entity.dimension.getEntities({
        maxDistance: 5,
        families: ["player"],
        location: entity.location
    });
    for (let i = 0; i < players.length; i++) {
        if (players[i].getGameMode() === "creative" || players[i].getGameMode() === "spectator")
            continue;
        entity.triggerEvent("awaken")
        return;
    }
}
function getNearestPlayer(entity) {
    const player = entity.dimension.getEntities({
        families: ['player'],
        maxDistance: 14,
        location: entity.location
    })[0];
    if (player === undefined)
        return undefined;
    return player;
}
function rotateToTarget(entity) {
    const target = getNearestPlayer(entity);
    if (target === undefined)
        return;
    const vToTarget = vector.subtract(target.location, entity.location);
    const angle = -(Math.atan2(vToTarget.x, vToTarget.z) * 180) / Math.PI;
    //mc.world.sendMessage(`Attack angle: ${angle}`);
    entity.setProperty('hf_mzs:y_rot', angle);
}

function dustEffect(entity) {
    for (let i = 0; i < 14; i++) {
        //mc.world.sendMessage(`${count}`)
        for (let j = 0; j < 14; j++) {
            if (Math.random() < 0.5)
                continue;
            const loc = {
                x: entity.location.x - 7 + i,
                y: entity.location.y + 5,
                z: entity.location.z - 7 + j
            };
            //mc.world.sendMessage(`${vector.string(loc)}}`)
            const block = entity.dimension.getBlock(loc);
            if (block === undefined)
                continue;
            if (block.typeId === "minecraft:cobblestone" || block.typeId === "minecraft:stone") {
                entity.runCommand(`/particle hf_mzs:wroughtnaut_room_dust ${vector.string(loc)}`)
                continue;
            }
        }
    }
}