import { Block, Entity, system, world } from "@minecraft/server";
import { namespace } from "../config/_config";
import ScriptingModule from "./scriptingModule";
import { registerViewTriggers } from "../config/viewTrigger";
export class ViewTrigger {
    constructor({ entities = [], blocks = [], minDistance = 0, maxDistance = 10, entityFov: entityFov = 45, firstTimeOnly = false, cooldown = 0, onSight, }) {
        this.entities = entities;
        this.blocks = blocks;
        this.minDistance = minDistance;
        this.maxDistance = maxDistance;
        this.entityFov = entityFov;
        this.firstTimeOnly = firstTimeOnly;
        this.cooldown = cooldown;
        this.onSight = onSight;
    }
    static register(config) {
        const trigger = new ViewTrigger(config);
        this.viewTriggers.push(trigger);
    }
    static initialize() {
        system.runInterval(() => {
            const players = world.getPlayers();
            players.forEach((player) => {
                ViewTrigger.viewTriggers.forEach((trigger, index) => {
                    const playerProperty = `${namespace}:viewTrigger_${index}`;
                    // Check dynamic properties
                    const triggeredBefore = player.getDynamicProperty(`${namespace}:${playerProperty}_firstTime`);
                    const lastTriggeredTime = player.getDynamicProperty(`${namespace}:${playerProperty}_lastTriggered`) ||
                        0;
                    const currentTick = system.currentTick;
                    // Check cooldown and firstTimeOnly properties
                    if (trigger.cooldown && currentTick - lastTriggeredTime < trigger.cooldown * 20)
                        return;
                    if (trigger.firstTimeOnly && triggeredBefore)
                        return;
                    const playerDirection = player.getViewDirection();
                    const nearbyEntities = world.getDimension("overworld").getEntities({
                        location: player.location,
                        maxDistance: trigger.maxDistance ?? 10,
                        minDistance: trigger.minDistance ?? 0,
                    });
                    // Handle entities in range
                    nearbyEntities.forEach((entity) => {
                        if (trigger.entities?.includes(entity.typeId) &&
                            this.isWithinFOV(player, playerDirection, entity, trigger.entityFov || 45)) {
                            this.triggerOnSight(player, trigger, entity);
                            player.setDynamicProperty(`${namespace}:${playerProperty}_lastTriggered`, currentTick);
                            if (trigger.firstTimeOnly) {
                                player.setDynamicProperty(`${namespace}:${playerProperty}_firstTime`, true);
                            }
                        }
                    });
                    const block = player.getBlockFromViewDirection({
                        maxDistance: trigger.maxDistance ?? 10,
                        includeLiquidBlocks: false,
                        includePassableBlocks: true,
                    })?.block;
                    if (!block)
                        return;
                    if (trigger.blocks?.includes(block?.typeId)) {
                        this.triggerOnSight(player, trigger, block);
                        player.setDynamicProperty(`${namespace}:${playerProperty}_lastTriggered`, currentTick);
                        if (trigger.firstTimeOnly) {
                            player.setDynamicProperty(`${namespace}:${playerProperty}_firstTime`, true);
                        }
                    }
                });
            });
        }, 3);
    }
    /**
     * Triggers the onSight event for the given player, entity, and trigger.
     */
    static triggerOnSight(player, trigger, target) {
        if (target instanceof Entity && trigger.onSight.function) {
            trigger.onSight.function(player, target);
        }
        if (target instanceof Block && trigger.onSight.function) {
            trigger.onSight.function(player, target);
        }
        if (trigger.onSight.sound) {
            player.playSound(trigger.onSight.sound);
        }
        if (trigger.onSight.message) {
            player.sendMessage(trigger.onSight.message);
        }
    }
    /**
     * Determines if an entity is within the player's FOV.
     * @param player The player object.
     * @param playerDirection The player's view direction vector.
     * @param entity The entity to check.
     * @param fov The field of view in degrees.
     * @returns True if the entity is within the FOV, false otherwise.
     */
    static isWithinFOV(player, playerDirection, entity, fov) {
        const entityPosition = entity.location;
        const playerPosition = player.location;
        // Calculate vector from player to entity
        const toEntity = {
            x: entityPosition.x - playerPosition.x,
            y: entityPosition.y - playerPosition.y,
            z: entityPosition.z - playerPosition.z,
        };
        const normToEntity = this.normalizeVector(toEntity);
        const normPlayerDirection = this.normalizeVector(playerDirection);
        // Calculate dot product between view direction and vector to entity
        const dotProduct = normPlayerDirection.x * normToEntity.x +
            normPlayerDirection.y * normToEntity.y +
            normPlayerDirection.z * normToEntity.z;
        const angle = Math.acos(dotProduct) * (180 / Math.PI);
        return angle < fov / 2;
    }
    /**
     * Normalizes a vector (scales it to a unit vector).
     * @param vector The vector to normalize.
     * @returns The normalized vector.
     */
    static normalizeVector(vector) {
        const length = Math.sqrt(vector.x * vector.x + vector.y * vector.y + vector.z * vector.z);
        return {
            x: vector.x / length,
            y: vector.y / length,
            z: vector.z / length,
        };
    }
}
ViewTrigger.viewTriggers = [];
export default class ViewTriggerModule extends ScriptingModule {
    constructor() {
        super("ViewTriggerModule");
        this.onInitialize = () => {
            registerViewTriggers();
        };
    }
}
