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

/** Нормированная раскладка материала в области показа (0..1). */
export type MaterialsOverlayLayout = {
  /** Центр по X относительно вьюпорта. */
  cx: number;
  /** Центр по Y относительно вьюпорта. */
  cy: number;
  /** Масштаб относительно «базового contain» (1 = по умолчанию). */
  scale: number;
  /** Свободный угол поворота на сессии, градусы. */
  rotationDeg: number;
};

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

/** Session-only: какие материалы сейчас показаны поверх сцены. */
export type MaterialsOverlayState = {
  revision: number;
  activeMaterialIds: MaterialId[];
  layouts: Record<string, MaterialsOverlayLayout>;
  /** Раскладка блока описаний легенды по materialId. */
  legendLayouts: Record<string, MaterialsOverlayLayout>;
  focusMaterialId: MaterialId | null;
  zoomTool: MaterialsZoomTool;
};

export const DEFAULT_MATERIALS_OVERLAY_LAYOUT: MaterialsOverlayLayout = {
  cx: 0.5,
  cy: 0.5,
  scale: 1,
  rotationDeg: 0,
};

export type MaterialsOverlayEvent =
  | { kind: 'show'; materialId: MaterialId; rotationDeg?: number }
  | { kind: 'hide' }
  | { kind: 'toggle'; materialId: MaterialId; rotationDeg?: number }
  | { kind: 'layout.set'; materialId: MaterialId; layout: MaterialsOverlayLayout }
  | { kind: 'legendLayout.set'; materialId: MaterialId; layout: MaterialsOverlayLayout }
  | { kind: 'zoomTool.set'; tool: MaterialsZoomTool }
  | { kind: 'zoomAt'; nx: number; ny: number; materialId?: MaterialId };

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

export function clampMaterialsLayout(layout: MaterialsOverlayLayout): MaterialsOverlayLayout {
  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: normalizeMaterialsRotation(layout.rotationDeg ?? 0),
  };
}

/** Zoom around normalized point so that point stays fixed. */
export function zoomMaterialsLayoutAt(
  layout: MaterialsOverlayLayout,
  nx: number,
  ny: number,
  factor: number,
): MaterialsOverlayLayout {
  const nextScale = layout.scale * factor;
  const clamped = clampMaterialsLayout({ ...layout, scale: nextScale });
  const ratio = clamped.scale / layout.scale;
  return clampMaterialsLayout({
    ...layout,
    cx: nx - (nx - layout.cx) * ratio,
    cy: ny - (ny - layout.cy) * ratio,
    scale: clamped.scale,
  });
}

function initialLegendLayout(): MaterialsOverlayLayout {
  return clampMaterialsLayout({
    ...DEFAULT_MATERIALS_OVERLAY_LAYOUT,
    cx: 0.82,
    cy: 0.5,
    scale: 0.85,
    rotationDeg: 0,
  });
}

export function defaultLegendLayoutForMaterial(): MaterialsOverlayLayout {
  return initialLegendLayout();
}
