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 = 30;

export function eventBehavior(event) {
    //mc.world.sendMessage(event.entity.typeId+':    '+event.eventId+'');
    //if (event.eventId !== "reenforce_movement" && event.eventId !== "step")
    //    mc.world.sendMessage(event.entity.typeId+':    '+event.eventId+'');
    if (event.eventId === "awaken")
        event.entity.triggerEvent("attack_res")
    if (event.eventId === "stand_up")
        event.entity.addEffect("slowness", 3.2, {
            amplifier: 10,
            showParticles: false
        });
    if (event.eventId === 'attack_ice_shoot') {
        const e = event.entity.dimension.getEntities({ location: event.entity.location, maxDistance: 64, type: 'player' });
        if(e[0]===undefined)
            return;
        event.entity.runCommand("/tp @s ~~~ facing @p");
        const p = event.entity.getHeadLocation();
        const r = vector.multiply(event.entity.getViewDirection(), 1);
        const v1 ={x: p.x+r.x, y: p.y+r.y, z: p.z+r.z};
        
        const v2 = {x: e[0].location.x-v1.x, y: (e[0].location.y+1)-v1.y, z: e[0].location.z-v1.z};
        
        const v3 = vector.normalize(v2);
        const proj = event.entity.dimension.spawnEntity("hf_mzs:frostmaw_projectile", v1);
        proj.setDynamicProperty("hf_mzs:x_dir", v3.x);
        proj.setDynamicProperty("hf_mzs:y_dir", v3.y);
        proj.setDynamicProperty("hf_mzs:z_dir", v3.z);
        proj.applyImpulse(vector.multiply(v3, 2.7));
        return;
    }
    if (event.eventId === 'attack_breath_shoot') {
        event.entity.addTag("hf_mzs_breathing");
        event.entity.setDynamicProperty("hf_mzs:breathing", 12);
        return;
    }
    if (event.eventId === 'attack_slam2') {
        const r = event.entity.getViewDirection();
        const entities = selectors.union({
            location: {
                x: event.entity.location.x +r.x*4, 
                y: event.entity.location.y+1, 
                z: event.entity.location.z +r.z*4
            },
            maxDistance: 4.5,
        }, ["player", "mob"] , event.entity.dimension, event.entity.id);

        event.entity.runCommand("/camerashake add @a[r=16] 1.3 0.9 positional")
        for (let 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(0, 0, 1.5, 1);
            entities[i].applyDamage(ATTACK_SLAM_DAMAGE, {
                cause: "entityAttack",
                damagingEntity: event.entity
            });
        }
        return;
    }
    if (event.eventId === 'attack_swipe2' || event.eventId === 'attack_double_swipe2' || event.eventId === 'attack_double_swipe3') {
        event.entity.runCommand("/tp @s ~~~ facing @p");
        const arc = selectors.getEntitiesArc(event.entity, ["player", "mob"], 7.5, 135);
        const r = event.entity.getViewDirection();
                        
        for (let i = 0; i < arc.length; i++) {
            if (arc[i]===undefined)
                continue;
            arc[i].applyKnockback(r.x, r.z, 2, 0.1);
            arc[i].applyDamage(10, {
                cause: "entityAttack",
                damagingEntity: event.entity
            });
        }
        //mc.world.sendMessage("swipe");
        return;
    }
    if (event.eventId === 'dodge') {
        const r = event.entity.getViewDirection();
        event.entity.applyImpulse({ x: -r.x*1.5, y: 0.9, z: -r.z*1.5 });
        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");
        }, 82);
        return;
    }
}
export function hurtBehavior(event) {
    event.hurtEntity.setProperty('hf_mzs:dodge_counter', Math.min(Math.max(event.hurtEntity.getProperty('hf_mzs:dodge_counter')+event.damage, 0), 16));
}
export function tick20(entity) {
    if (entity.getProperty("hf_mzs:sleep_timer") && entity.getProperty('hf_mzs:sleep_timer_i') > 0)
        entity.setProperty('hf_mzs:sleep_timer_i', entity.getProperty('hf_mzs:sleep_timer_i')-1)
    else if (entity.getProperty("hf_mzs:sleep_timer") && entity.getProperty('hf_mzs:sleep_timer_i') === 0) {
        entity.triggerEvent("fall_asleep");
        return;
    }
    //else if (!entity.getProperty("hf_mzs:awaking") && !entity.getProperty("hf_mzs:death") && 
    //    entity.getProperty("hf_mzs:can_transition") && entity.getProperty("hf_mzs:attack_mode")==="none"
    //)
    //    isStuck(entity);
    if (entity.getProperty('hf_mzs:cooldown_roar') > 0)
        entity.setProperty('hf_mzs:cooldown_roar', entity.getProperty('hf_mzs:cooldown_roar')-1)
    if (entity.getProperty('hf_mzs:cooldown_ice') > 0)
        entity.setProperty('hf_mzs:cooldown_ice', entity.getProperty('hf_mzs:cooldown_ice')-1)
    if (entity.getProperty('hf_mzs:cooldown_dodge') > 0)
        entity.setProperty('hf_mzs:cooldown_dodge', entity.getProperty('hf_mzs:cooldown_dodge')-1)
    if (entity.getProperty('hf_mzs:dodge_counter') > 0)
        entity.setProperty('hf_mzs:dodge_counter', Math.min(Math.max(entity.getProperty('hf_mzs:dodge_counter')-4, 0), 30))
    if (entity.getProperty('hf_mzs:cooldown_slam') > 0)
        entity.setProperty('hf_mzs:cooldown_slam', entity.getProperty('hf_mzs:cooldown_slam')-1)
    if (entity.getProperty('hf_mzs:cooldown_breath') > 0)
        entity.setProperty('hf_mzs:cooldown_breath', entity.getProperty('hf_mzs:cooldown_breath')-1)
}
export function tick5(entity){
    if (entity.getProperty("hf_mzs:sleeping"))
        checkForPlayer(entity);
    if (entity.getProperty("hf_mzs:sleeping") && entity.getProperty("hf_mzs:has_crystal"))
        checkAtHand(entity);
    if (entity.getProperty("hf_mzs:roaring")===true)
        roar(entity);
        
    if (entity.getDynamicProperty("hf_mzs:breathing")>0) 
        iceBreath(entity);
}
export function tick1(entity) {
    if (!entity.getProperty("hf_mzs:roaring"))
        pushEntities(entity);
    if (entity.getProperty("hf_mzs:sleeping") || entity.getProperty("hf_mzs:awaking")) {
        entity.setRotation(entity.getRotation());
        entity.teleport(entity.location);
    }
}

function pushEntities(entity) {
    const entities = selectors.union({
        location: entity.location,
        maxDistance: 3.4,
        excludeFamilies: [ "inanimate" ]
    }, ["player", "mob"] , entity.dimension, entity.id);

    for (let i = 0; i < entities.length; i++) {
        if (entities[i] === undefined)
            continue;
        var v = vector.subtract(entities[i].location, entity.location);
        if (entities[i].typeId === "minecraft:player" || (entities[i].typeId !== "minecraft:player" && vector.magnitude(v)<=2.7))
            entities[i].applyKnockback(v.x, v.y, 1.5, 0);
    }
}
function roar(entity) {
    const entities = selectors.union({
        location: entity.location,
        maxDistance: 7,
    }, ["player", "mob"] , entity.dimension, entity.id);
        
    for (let i = 0; i < entities.length; i++) {
        if (entities[i] === undefined)
            continue;
        var v = vector.subtract(entities[i].location, entity.location);
        entities[i].applyKnockback(v.x, v.y, 2, 0.4);
    }
}
function iceBreath(entity) {
    entity.setDynamicProperty("hf_mzs:breathing", entity.getDynamicProperty("hf_mzs:breathing")-1);
    
    entity.runCommand("/tp @s ~~~ facing @p[r=16]");
    entityUtils.freezeWater(entity);
    var arc = selectors.getEntitiesArc(entity, ["player", "mob"], 15, 60);
                    
    for (var i = 0; i < arc.length; i++) {
        if (arc[i]===undefined)
            continue;
        arc[i].applyDamage(1, {
            cause: "freezing",
            damagingEntity: entity
        });
        effects.applyColdEffect(arc[i], 1);
        arc[i].teleport(arc[i].location);
    }
}

function checkForPlayer(entity) {
    const players = entity.dimension.getEntities({
        maxDistance: 7.5,
        families: ["player"],
        location: entity.location
    });
    for (let i = 0; i < players.length; i++) {
        if (players[i].getGameMode() === "creative" || players[i].getGameMode() === "spectator" || 
            players[i].getEffect("invisibility") !== undefined    
        )
            continue;
        if (entity.getProperty("hf_mzs:has_crystal"))
            entity.triggerEvent("awaken_ice_crystal");
        else
            entity.triggerEvent("awaken_no_ice_crystal");
        return;
    }
}
function checkAtHand(entity) {
    let handPos = vector.add(entity.location, vector.multiply(vector.flatten(entity.getViewDirection(), 'y'), 3.3));
    handPos = vector.add(handPos, vector.multiply(vector.cross(vector.flatten(entity.getViewDirection(), 'y'), vector.up), 2.7));
    const playersAtHand = entity.dimension.getEntities({
        families: ["player"],
        maxDistance: 0.7,
        location: handPos
    });
    //mc.world.sendMessage(`${vector.string(handPos)}`);
    for (let i = 0; i < playersAtHand.length; i++) {
        // mc.world.sendMessage(`bbb}`);
        if (playersAtHand[i].getGameMode() === "creative" || playersAtHand[i].getGameMode() === "spectator")
            continue;
        playersAtHand[i].dimension.spawnItem(new mc.ItemStack("hf_mzs:ice_crystal"), playersAtHand[i].location);
        playersAtHand[i].removeEffect("invisibility");
        entity.triggerEvent("awaken_no_ice_crystal");
        return;
    }
}

const blockFilters = {
    maxDistance: 4.5,
    includePassableBlocks: false,
    includeLiquidBlocks: false
}
function isStuck(entity) {
    //mc.world.sendMessage("Checking if stuck");
    const pos = vector.add(entity.location, vector.up);

    const block1 = entity.dimension.getBlockFromRay(pos, vector.right, blockFilters);
    const block2 = entity.dimension.getBlockFromRay(pos, vector.left, blockFilters);
    const block3 = entity.dimension.getBlockFromRay(pos, vector.forward, blockFilters);
    const block4 = entity.dimension.getBlockFromRay(pos, vector.back, blockFilters);

    const sum = (block1 !== undefined) + (block2 !== undefined) + (block3 !== undefined) + (block4 !== undefined)
    //mc.world.sendMessage(`${sum}`);
    if (sum >= 3)
        entity.triggerEvent("dodge");
}