/**
 * Точки взаимодействия (перенос идеи v1 как чистых данных): реестр
 * «интерактивов» {id, pos, radius, label} + чистая функция поиска ближайшей
 * в радиусе. Регистрация/удаление — игра; движок только считает ближайшую
 * точку к герою и говорит, можно ли взаимодействовать.
 */

/** Точка, около которой герою доступно взаимодействие (E). */
export interface Interactable {
    /** Идентификатор (стабильный, для моста и диалогов). */
    id: string;
    /** Мировая позиция центра (x, y — не учитывается, z) — горизонтальная дистанция. */
    pos: readonly [number, number, number];
    /** Радиус доступности (в вокселях). */
    radius: number;
    /** Подсказка для игрока/агента («Поговорить», «Осмотреть»). */
    label: string;
    /** Граф диалога, если точка говорит (связка точка ↔ диалог — данные). */
    dialogueId?: string;
}

/** Расстояние до точки и сама точка (для сортировки/подсказки «какая ближе»). */
export interface InteractableHit<T> {
    item: T;
    dist: number;
}

/** Горизонтальное (x-z) расстояние от позиции до точки. */
function horizontalDist(
    pos: readonly [number, number, number],
    it: { pos: readonly [number, number, number] },
): number {
    const dx = it.pos[0] - pos[0];
    const dz = it.pos[2] - pos[2];
    return Math.hypot(dx, dz);
}

/** Ближайшая доступная точка (в радиусе) или null. Y не учитывается. */
export function nearestInteractable<T extends Interactable>(
    registry: readonly T[],
    pos: readonly [number, number, number],
): T | null {
    let best: T | null = null;
    let bestDist = Infinity;
    for (const it of registry) {
        const d = horizontalDist(pos, it);
        if (d <= it.radius && d < bestDist) {
            best = it;
            bestDist = d;
        }
    }
    return best;
}

/** Все доступные точки с расстояниями, ближе — раньше (для отладки/моста). */
export function interactablesInRadius<T extends Interactable>(
    registry: readonly T[],
    pos: readonly [number, number, number],
): InteractableHit<T>[] {
    return registry
        .map((item) => ({ item, dist: horizontalDist(pos, item) }))
        .filter((h) => h.dist <= h.item.radius)
        .sort((a, b) => a.dist - b.dist);
}