import * as mc from "@minecraft/server";

export function highlightBlock(block) {

    let location = block.location;
    let dimension = block.dimension.id;

    let mvm = new mc.MolangVariableMap();
    mvm.setFloat(`variable.dirx`, 0);
    mvm.setFloat(`variable.diry`, 1);
    mvm.setFloat(`variable.dirz`, 0);
    mc.world.getDimension(dimension).spawnParticle('pb_scraft:block_marker', { x: location.x + 0.5, y: location.y - 0.01, z: location.z + 0.5 }, mvm);
    mc.world.getDimension(dimension).spawnParticle('pb_scraft:block_marker', { x: location.x + 0.5, y: location.y + 1.01, z: location.z + 0.5 }, mvm);

    mvm.setFloat(`variable.dirx`, 1);
    mvm.setFloat(`variable.diry`, 0);
    mvm.setFloat(`variable.dirz`, 0);
    mc.world.getDimension(dimension).spawnParticle('pb_scraft:block_marker', { x: location.x + 1.01, y: location.y + 0.5, z: location.z + 0.5 }, mvm);
    mc.world.getDimension(dimension).spawnParticle('pb_scraft:block_marker', { x: location.x - 0.01, y: location.y + 0.5, z: location.z + 0.5 }, mvm);

    mvm.setFloat(`variable.dirx`, 0);
    mvm.setFloat(`variable.diry`, 0);
    mvm.setFloat(`variable.dirz`, 1);
    mc.world.getDimension(dimension).spawnParticle('pb_scraft:block_marker', { x: location.x + 0.5, y: location.y + 0.5, z: location.z + 1.01 }, mvm);
    mc.world.getDimension(dimension).spawnParticle('pb_scraft:block_marker', { x: location.x + 0.5, y: location.y + 0.5, z: location.z + 0.01 }, mvm);
}

export function getMainhandItem(player) {
    return player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand).getItem();
}

export function randomLocationDisc(location, radius) {
    return { x: location.x + randomNum(-radius, radius), y: location.y, z: location.z + randomNum(-radius, radius) }
}

export function getDistance(a, b) {
    const dx = b.x - a.x;
    const dy = b.y - a.y;
    const dz = b.z - a.z;
    const distance = Math.hypot(dx, dy, dz);
    return distance;
}

export function getRandomInt(min, max) {
    min = Math.ceil(min);
    max = Math.floor(max);
    return Math.floor(Math.random() * (max - min + 1)) + min;
}

export function randomWholeNum(min, max) {
    const maxPlus1 = max + 1;
    let result = Math.random() * (max - min) + min;
    //return a random whole number
    return Math.round(result);
}

export function randomNum(min, max) {
    //return a random number
    return Math.random() * (max - min) + min;
}

export function isEntityinCone(location, entity, view_vector, deviation_angle) {
    const angle = Math.abs(angle2D(location, entity.location, view_vector));
    const min = 180 - (deviation_angle / 2)
    if (angle > min) return true;
}

function angle2D(source_location, target_location, view_vector) {
    let dir_vector = { x: view_vector.x, y: view_vector.z, z: 0 };
    let target_vector = { x: source_location.x - target_location.x, y: source_location.z - target_location.z, z: 0 };

    let angle = Math.atan2(target_vector.y, target_vector.x) - Math.atan2(dir_vector.y, dir_vector.x);
    angle *= (180 / Math.PI);

    if (angle > 180) angle = -(180 - (angle - 180));
    if (angle < -180) angle = (180 + (angle + 180));

    return angle
}

export function rotateVector2D(vec, angle) {
    angle = angle * (Math.PI / 180);
    return {
        x: vec.x * Math.cos(angle) - vec.z * Math.sin(angle),
        y: vec.y,
        z: vec.x * Math.sin(angle) + vec.z * Math.cos(angle)
    };
}

export function runCooldown(player) {
    const item = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand).getItem();
    if (item == undefined) return;
    if (!item.hasComponent("minecraft:cooldown")) return;
    const cooldown = item.getComponent("minecraft:cooldown");
    cooldown.startCooldown(player);
}

export function setCooldown(player, value) {
    const item = player.getComponent(mc.EntityEquippableComponent.componentId).getEquipmentSlot(mc.EquipmentSlot.Mainhand).getItem();
    if (item == undefined) return;
    if (!item.hasComponent("minecraft:cooldown")) return;
    const cooldown = item.getComponent("minecraft:cooldown");
    player.startItemCooldown(cooldown.cooldownCategory, value);
}

export function targetMobMonster(location, dimensionId, radius) {
    let target_entities = mc.world.getDimension(dimensionId).getEntities({ location: location, families: ["mob"], excludeFamilies: ["projectile", "prop", "npc", "spell", "inanimate"], maxDistance: radius });
    target_entities = target_entities.concat(mc.world.getDimension(dimensionId).getEntities({ location: location, families: ["monster"], excludeFamilies: ["projectile", "prop", "npc", "spell", "inanimate"], maxDistance: radius }));
    return target_entities;
}

export class itemManager {
    static reduceDurability(player, item, reduceAmount) {
        const comp = item.getComponent(mc.ItemDurabilityComponent.componentId);
        if (comp.damage + reduceAmount <= comp.maxDurability) {
            comp.damage = comp.damage + reduceAmount;
            return item;
        } else {
            player.dimension.playSound("random.break", player.location);
            return undefined;
        }
    }
    static addDurability(player, item, addAmount) {
        const comp = item.getComponent(mc.ItemDurabilityComponent.componentId);
        if (comp.damage - addAmount < 0) {
            comp.damage = 0;
            return item;
        } else {
            comp.damage = comp.damage - comp.addAmount;
            return item;
        }
    }
    static reduceAmount(item, reduceBy) {
        const amount = item.amount;
        if (amount - reduceBy <= 0) {
            return undefined;
        } else {
            item.amount = amount - reduceBy;
            return item;
        }
    }
}

export function locString(location) {
    return "" + location.x + "," + location.y + "," + location.z;
}

export function applyImpulsePlayer(player, vector) {
    const { x, y, z } = vector;
    const horizontal = Math.sqrt(x * x + z * z) * 2.0;
    player.applyKnockback(x, z, horizontal, y);
}

export function locationIsValid(dimension, location) {
    try {
        mc.world.getDimension(dimension.id).getBlock(location)
    }
    catch (error) {
        return false;
    };
    return true;
}