import { useCursor } from '@threlte/extras';
import { MathUtils, Matrix4, Quaternion, Vector2 } from 'three';
import { traits, useTrait, useWorld } from '../../../ecs';
import { updateHoverInfo } from '../../../HoverUpdater.svelte';
import { OrientationVector } from '../../../three/OrientationVector';
const tempHoverMatrix = new Matrix4();
const hoverQuat = new Quaternion();
const hoverOv = new OrientationVector();
const infoToLocalMatrix = (info, out) => {
    hoverOv.set(info.oX, info.oY, info.oZ, MathUtils.degToRad(info.theta));
    hoverOv.toQuaternion(hoverQuat);
    out.makeRotationFromQuaternion(hoverQuat);
    out.setPosition(info.x, info.y, info.z);
};
export const useEntityEvents = (entity) => {
    const down = new Vector2();
    const world = useWorld();
    const cursor = useCursor();
    const invisible = useTrait(entity, traits.InheritedInvisible);
    const onpointerenter = (event) => {
        if (invisible.current)
            return;
        event.stopPropagation();
        cursor.onPointerEnter();
        const currentEntity = entity();
        if (currentEntity && !currentEntity.has(traits.Hovered)) {
            const hoverInfo = updateHoverInfo(currentEntity, event);
            if (hoverInfo) {
                infoToLocalMatrix(hoverInfo, tempHoverMatrix);
                const worldMatrix = currentEntity.get(traits.WorldMatrix);
                const composed = new Matrix4();
                if (worldMatrix) {
                    composed.copy(worldMatrix).multiply(tempHoverMatrix);
                }
                else {
                    composed.copy(tempHoverMatrix);
                }
                currentEntity.add(traits.InstancedMatrix({
                    matrix: composed,
                    index: hoverInfo.index,
                }));
            }
            currentEntity.add(traits.Hovered);
        }
    };
    const onpointermove = (event) => {
        if (invisible.current)
            return;
        event.stopPropagation();
        const currentEntity = entity();
        if (currentEntity?.has(traits.Hovered)) {
            const hoverInfo = updateHoverInfo(currentEntity, event);
            if (!hoverInfo)
                return;
            infoToLocalMatrix(hoverInfo, tempHoverMatrix);
            const instanced = currentEntity.get(traits.InstancedMatrix);
            if (!instanced)
                return;
            const worldMatrix = currentEntity.get(traits.WorldMatrix);
            if (worldMatrix) {
                instanced.matrix.copy(worldMatrix).multiply(tempHoverMatrix);
            }
            else {
                instanced.matrix.copy(tempHoverMatrix);
            }
            instanced.index = hoverInfo.index;
            currentEntity.changed(traits.InstancedMatrix);
        }
    };
    const onpointerleave = (event) => {
        event.stopPropagation();
        cursor.onPointerLeave();
        const currentEntity = entity();
        if (currentEntity?.has(traits.Hovered)) {
            currentEntity.remove(traits.Hovered);
        }
        if (currentEntity?.has(traits.InstancedMatrix)) {
            currentEntity.remove(traits.InstancedMatrix);
        }
    };
    const onpointerdown = (event) => {
        if (invisible.current)
            return;
        down.copy(event.pointer);
    };
    const onclick = (event) => {
        if (invisible.current) {
            return;
        }
        event.stopPropagation();
        if (down.distanceToSquared(event.pointer) >= 0.1) {
            return;
        }
        const currentEntity = entity();
        if (!currentEntity)
            return;
        if (event.nativeEvent.shiftKey) {
            if (currentEntity.has(traits.Selected)) {
                currentEntity.remove(traits.Selected);
            }
            else {
                currentEntity.add(traits.Selected);
            }
        }
        else {
            for (const entity of world.query(traits.Selected)) {
                if (entity !== currentEntity) {
                    entity.remove(traits.Selected);
                }
            }
            if (!currentEntity.has(traits.Selected)) {
                currentEntity.add(traits.Selected);
            }
        }
        if (event.instanceId || event.batchId) {
            currentEntity.add(traits.InstanceId(event.instanceId ?? event.batchId));
        }
    };
    $effect(() => {
        if (invisible.current) {
            cursor.onPointerLeave();
            const currentEntity = entity();
            if (currentEntity?.has(traits.Hovered)) {
                currentEntity.remove(traits.Hovered);
            }
            if (currentEntity?.has(traits.InstancedMatrix)) {
                currentEntity.remove(traits.InstancedMatrix);
            }
        }
    });
    return {
        onpointerenter,
        onpointermove,
        onpointerleave,
        onpointerdown,
        onclick,
    };
};
