import {
    Container,
    Dimension,
    Entity,
    EntityInventoryComponent,
    GameMode,
    TicksPerSecond,
    system,
} from "@minecraft/server";
import { EntityObject } from "../global_api/EntityRuntime";
import { Vector2 } from "../global_api/Math";

export class Utils {
    /**
     * @param {EntityObject} obj
     * @param {number} distance
     * @returns {import("@minecraft/server").EntityRaycastHit[]}
     */
    static featchViewEntities(obj, distance, height = 4, width = 10) {
        const entity = obj.getEntity();

        return this.featchEntityFromRotation(
            entity.dimension,
            entity.location,
            new Vector2(
                obj.getEntity().getViewDirection().x,
                obj.getEntity().getViewDirection().z
            ).getDegress(),
            distance,
            height,
            width
        ).filter((e) => {
            if (e && e.entity.typeId == "minecraft:player") {
                return e.entity.getGameMode() != GameMode.Creative;
            }
            return (
                e &&
                e.entity &&
                e.entity.typeId != entity.typeId &&
                e.entity.typeId != "minecraft:item"
            );
        });
    }

    /**
     * @param {Entity} entity
     * @param {import("@minecraft/server").Vector3} vector3
     */
    static applyForce(entity, vector3) {
        try {
            entity.applyImpulse(vector3);
        } catch (e) {
            try {
                //entity.applyKnockback(vector3.x, vector3.z, 1, vector3.y);
                entity.applyKnockback(Math.sign(vector3.x), 0, Math.abs(vector3.x), vector3.y / 2);
                entity.applyKnockback(0, Math.sign(vector3.z), Math.abs(vector3.z), vector3.y / 2);
            } catch (e) {
                // log("Utils", "Cannot apply force to: ", entity?.typeId, e);
            }
        }
    }

    /**
     * @param {number} distance
     * @param {Dimension} dimension
     * @returns {import("@minecraft/server").EntityRaycastHit[]}
     */
    static featchEntityFromView(dimension, location, viewDir, distance, height = 4, width = 10) {
        const entityData = {};
        for (let y = 0; y < height; y++)
            for (let d = 0; d < distance; d++) {
                const position = {
                    x: location.x + viewDir.x * d * 2,
                    y: location.y + viewDir.y * d * 2 + y,
                    z: location.z + viewDir.z * d * 2,
                };
                try {
                    dimension
                        .getEntities({
                            location: position,
                            maxDistance: width,
                        })
                        .forEach((e) => {
                            entityData[e.id] = {
                                entity: e,
                                distance: -1,
                            };
                        });
                    //dimension.spawnParticle("pixell_bbo:sweet_ray", position)
                } catch (e) {}
            }
        return Object.values(entityData);
    }
    /**
     * @param {number} distance
     * @param {Dimension} dimension
     * @returns {import("@minecraft/server").EntityRaycastHit[]}
     */
    static featchEntityFromRotation(
        dimension,
        location,
        rotationY,
        distance,
        height = 4,
        width = 10
    ) {
        const entityData = {};
        distance *= 2;
        dimension
            .getEntities({
                location,
                maxDistance: distance * 3,
            })
            .forEach((e) => {
                if (e.typeId.startsWith("pixell_bbo")) return;

                const offset = new Vector2(
                    e.location.x - location.x,
                    e.location.z - location.z
                ).rotate(rotationY);

                //log("S", offset, distance, width)
                if (offset.x >= 0 && offset.x <= distance && Math.abs(offset.y) <= width) {
                    entityData[e.id] = {
                        distance: offset.x,
                        entity: e,
                    };
                }
            });

        return Object.values(entityData);
    }

    static post(callback, secs) {
        system.runTimeout(() => {
            try {
                callback();
            } catch (e) {
                // log("CallbackError", e);
            }
        }, secs * TicksPerSecond);
    }
}

/**
 * @param {Player} player
 * @param {string} itemID
 * @param {number} amount
 */
export function hasItems(player, itemID, amount = 1) {
    const container = player.getComponent(EntityInventoryComponent.componentId).container;
    for (let i = 0; i < container.size; i++) {
        const slot = container.getSlot(i);
        if (slot.hasItem() && slot.typeId == itemID) {
            amount -= slot.amount;
        }
        if (amount <= 0) return true;
    }
    return false;
}

/**
 *
 * @param {Entity} entity
 * @param {string} itemId
 */
export function getItemAmount(entity, itemId) {
    /**
     * @type {Container|undefined}
     */
    const container = entity.getComponent(EntityInventoryComponent.componentId).container;

    if (!container) return;

    let amount = 0;

    for (let i = 0; i < container.size; i++) {
        const item = container.getItem(i);

        if (!item) continue;

        if (item.typeId == itemId) {
            amount += item.amount;
        }
    }

    return amount;
}
