/** Легенда материала: пункты + маркеры на изображении. */

export type MaterialLegendItemId = string & { readonly __brand: 'MaterialLegendItemId' };
export type MaterialLegendMarkerId = string & { readonly __brand: 'MaterialLegendMarkerId' };

export function asMaterialLegendItemId(id: string): MaterialLegendItemId {
  return id as MaterialLegendItemId;
}

export function asMaterialLegendMarkerId(id: string): MaterialLegendMarkerId {
  return id as MaterialLegendMarkerId;
}

export type MaterialLegendItem = {
  id: MaterialLegendItemId;
  /** Автономер (1..n), может повторяться у нескольких маркеров. */
  number: number;
  text: string;
};

export type MaterialLegendMarker = {
  id: MaterialLegendMarkerId;
  number: number;
  /** 0..1 относительно изображения материала. */
  nx: number;
  ny: number;
};

export type MaterialLegend = {
  enabled: boolean;
  items: MaterialLegendItem[];
  markers: MaterialLegendMarker[];
};

export const EMPTY_MATERIAL_LEGEND: MaterialLegend = {
  enabled: false,
  items: [],
  markers: [],
};

export function clampLegendCoord(v: number): number {
  if (!Number.isFinite(v)) return 0.5;
  return Math.max(0, Math.min(1, v));
}

export function normalizeMaterialLegend(raw: unknown): MaterialLegend | undefined {
  if (!raw || typeof raw !== 'object') return undefined;
  const o = raw as {
    enabled?: boolean;
    items?: unknown[];
    markers?: unknown[];
  };
  const items: MaterialLegendItem[] = (Array.isArray(o.items) ? o.items : [])
    .map((it) => {
      if (!it || typeof it !== 'object') return null;
      const x = it as { id?: string; number?: number; text?: string };
      if (!x.id) return null;
      const number = typeof x.number === 'number' && Number.isFinite(x.number) ? Math.max(1, Math.round(x.number)) : 1;
      return {
        id: asMaterialLegendItemId(String(x.id)),
        number,
        text: typeof x.text === 'string' ? x.text : '',
      };
    })
    .filter((x): x is MaterialLegendItem => Boolean(x));
  const markers: MaterialLegendMarker[] = (Array.isArray(o.markers) ? o.markers : [])
    .map((m) => {
      if (!m || typeof m !== 'object') return null;
      const x = m as { id?: string; number?: number; nx?: number; ny?: number };
      if (!x.id) return null;
      const number = typeof x.number === 'number' && Number.isFinite(x.number) ? Math.max(1, Math.round(x.number)) : 1;
      return {
        id: asMaterialLegendMarkerId(String(x.id)),
        number,
        nx: clampLegendCoord(x.nx ?? 0.5),
        ny: clampLegendCoord(x.ny ?? 0.5),
      };
    })
    .filter((x): x is MaterialLegendMarker => Boolean(x));
  return {
    enabled: Boolean(o.enabled),
    items,
    markers,
  };
}

/** Следующий автономер = max(items.number)+1 или 1. */
export function nextLegendNumber(items: readonly MaterialLegendItem[]): number {
  let max = 0;
  for (const it of items) {
    if (it.number > max) max = it.number;
  }
  return max + 1;
}

type ContentRect = { x: number; y: number; w: number; h: number };

/**
 * Размер неповёрнутого display-box картинки внутри AABB (`contentRect` от RotatedImage).
 * Маркеры легенды хранятся в UV этого box (как в MaterialOverlay), а не в AABB.
 */
export function legendImageDisplaySize(
  contentRect: ContentRect,
  rotationDeg: 0 | 90 | 180 | 270,
): { iw: number; ih: number } {
  if (rotationDeg === 90 || rotationDeg === 270) {
    return { iw: contentRect.h, ih: contentRect.w };
  }
  return { iw: contentRect.w, ih: contentRect.h };
}

/** Экранная точка относительно хоста → UV изображения (0..1). */
export function hostPointToLegendImageUv(
  hostX: number,
  hostY: number,
  contentRect: ContentRect,
  rotationDeg: 0 | 90 | 180 | 270,
): { x: number; y: number } {
  const { iw, ih } = legendImageDisplaySize(contentRect, rotationDeg);
  if (iw < 1e-6 || ih < 1e-6) return { x: 0.5, y: 0.5 };
  const cx = contentRect.x + contentRect.w / 2;
  const cy = contentRect.y + contentRect.h / 2;
  const dx = hostX - cx;
  const dy = hostY - cy;
  const rad = (-rotationDeg * Math.PI) / 180;
  const cos = Math.cos(rad);
  const sin = Math.sin(rad);
  const lx = dx * cos - dy * sin;
  const ly = dx * sin + dy * cos;
  return {
    x: clampLegendCoord((lx + iw / 2) / iw),
    y: clampLegendCoord((ly + ih / 2) / ih),
  };
}

/** UV изображения → позиция центра маркера в координатах хоста (px). */
export function legendImageUvToHostPoint(
  nx: number,
  ny: number,
  contentRect: ContentRect,
  rotationDeg: 0 | 90 | 180 | 270,
): { x: number; y: number } {
  const { iw, ih } = legendImageDisplaySize(contentRect, rotationDeg);
  const lx = (nx - 0.5) * iw;
  const ly = (ny - 0.5) * ih;
  const rad = (rotationDeg * Math.PI) / 180;
  const cos = Math.cos(rad);
  const sin = Math.sin(rad);
  return {
    x: contentRect.x + contentRect.w / 2 + (lx * cos - ly * sin),
    y: contentRect.y + contentRect.h / 2 + (lx * sin + ly * cos),
  };
}
