import type { NpcId } from './ids';

/** Нормированная раскладка аватара НПС в области показа (0..1). */
export type NpcsOverlayLayout = {
  cx: number;
  cy: number;
  scale: number;
  /** Свободный угол поворота, градусы. */
  rotationDeg: number;
};

export type NpcsZoomTool = 'zoomIn' | 'zoomOut' | null;

/** Session-only: какие НПС сейчас показаны поверх сцены (только аватары). */
export type NpcsOverlayState = {
  revision: number;
  /** Порядок выделения / показа описаний. */
  activeNpcIds: NpcId[];
  layouts: Record<string, NpcsOverlayLayout>;
  /** На кого действует zoom, если клик не попал в конкретный аватар. */
  focusNpcId: NpcId | null;
  zoomTool: NpcsZoomTool;
};

export const DEFAULT_NPCS_OVERLAY_LAYOUT: NpcsOverlayLayout = {
  cx: 0.5,
  cy: 0.5,
  scale: 1,
  rotationDeg: 0,
};

export type NpcsOverlayEvent =
  | { kind: 'show'; npcId: NpcId }
  | { kind: 'hide' }
  | { kind: 'toggle'; npcId: NpcId }
  | { kind: 'layout.set'; npcId: NpcId; layout: NpcsOverlayLayout }
  | { kind: 'zoomTool.set'; tool: NpcsZoomTool }
  | { kind: 'zoomAt'; nx: number; ny: number; npcId?: NpcId };

/** Нормализация угла в диапазон [0, 360). */
export function normalizeNpcsRotation(deg: number): number {
  if (!Number.isFinite(deg)) return 0;
  const n = deg % 360;
  return n < 0 ? n + 360 : n;
}

export function clampNpcsLayout(layout: NpcsOverlayLayout): NpcsOverlayLayout {
  return {
    cx: Math.min(1.2, Math.max(-0.2, layout.cx)),
    cy: Math.min(1.2, Math.max(-0.2, layout.cy)),
    scale: Math.min(8, Math.max(0.15, layout.scale)),
    rotationDeg: normalizeNpcsRotation(layout.rotationDeg ?? 0),
  };
}

export function zoomNpcsLayoutAt(
  layout: NpcsOverlayLayout,
  nx: number,
  ny: number,
  factor: number,
): NpcsOverlayLayout {
  const nextScale = layout.scale * factor;
  const clamped = clampNpcsLayout({ ...layout, scale: nextScale });
  const ratio = clamped.scale / layout.scale;
  return clampNpcsLayout({
    ...layout,
    cx: nx - (nx - layout.cx) * ratio,
    cy: ny - (ny - layout.cy) * ratio,
    scale: clamped.scale,
  });
}
