import { world, system } from "@minecraft/server";

class Vector3 {
    constructor(x, y, z) {
        this.x = x;
        this.y = y;
        this.z = z;
    }

    static fromLocation(location) {
        return new Vector3(location.x, location.y, location.z);
    }

    subtract(other) {
        return new Vector3(this.x - other.x, this.y - other.y, this.z - other.z);
    }

    magnitude() {
        return Math.sqrt(this.x ** 2 + this.y ** 2 + this.z ** 2);
    }

    normalize() {
        const length = this.magnitude();
        return new Vector3(this.x / length, this.y / length, this.z / length);
    }

    dot(other) {
        return this.x * other.x + this.y * other.y + this.z * other.z;
    }
}
class LookAtEntityComponent {
    constructor(actor, options) {
        this.actor = actor;
        this.options = options || {};
        this.loopHandle = null;

        this.init();
    }

    init() {
        this.loopHandle = system.runInterval(() => this.checkLookCondition(), 20); // Cada 20 ticks
    }

    checkLookCondition() {
        if (!this.isActorValid()) return; // Verifica si la entidad aún existe

        const players = world.getPlayers();
        for (const player of players) {
            if (this.isPlayerLookingAtEntity(player)) {
                this.actor.runCommand(`playanimation @s animation.aft_pb.outline`);
                return;
            } else {
                this.actor.runCommand(`playanimation @s animation.aft_pb.remove_outline`);
            }
        }
    }

    isActorValid() {
        try {
            // Intenta acceder a una propiedad básica
            this.actor.location;
            return true;
        } catch {
            // Si no es válida, elimina el loop asociado a esta instancia
            this.remove();
            return false;
        }
    }

    isPlayerLookingAtEntity(player) {
        const playerViewDirection = Vector3.fromLocation(player.getViewDirection());
        const playerPosition = Vector3.fromLocation(player.location);
        const entityPosition = Vector3.fromLocation(this.actor.location);

        const directionToEntity = entityPosition.subtract(playerPosition);
        const distance = directionToEntity.magnitude();

        // Aseguramos que la distancia esté dentro del rango
        if (distance > this.options.viewDistance) return false;

        // Si el jugador está muy cerca, asumimos que está mirando la entidad
        if (distance < 1) return true;

        // Normalizamos la dirección y calculamos el ángulo con el producto punto
        const normalizedDirectionToEntity = directionToEntity.normalize();
        const dotProduct = playerViewDirection.dot(normalizedDirectionToEntity);

        // Detectar si el jugador está mirando la entidad con un rango angular amplio
        return dotProduct > 0.85;
    }

    remove() {
        if (this.loopHandle) {
            system.clearRun(this.loopHandle);
            this.loopHandle = null;
        }
    }
}

const trackedEntities = new Map();

system.runInterval(() => {
    const dimension = world.getDimension("overworld");
    const entities = dimension.getEntities({ families: ["pet_block"], tags: ["tamed"] });

    for (const entity of entities) {
        if (!trackedEntities.has(entity.id)) {
            trackedEntities.set(entity.id, new LookAtEntityComponent(entity, { viewDistance: 5 }));
        }
    }

    // Limpiar entidades que ya no existen
    for (const [id, component] of trackedEntities) {
        if (!dimension.getEntities({ id }).length) {
            component.remove();
            trackedEntities.delete(id);
        }
    }
}, 20); // Cada 20 ticks