import { HELP_SECTION_IDS, type HelpSectionId } from './helpSections';

/**
 * Короткие имена разделов в перекрёстных ссылках
 * (когда в тексте не полное title, напр. «Эффекты» вместо «Эффекты поля и действий»).
 */
export const HELP_SECTION_LINK_ALIASES: Partial<Record<HelpSectionId, readonly string[]>> = {
  effects: ['Эффекты', 'Effects'],
  presentation: ['Презентация', 'Presentation'],
  grid: ['Сетка', 'Grid'],
  controlPanel: ['Пульт'],
  players: ['Игроки', 'Players'],
};

export type HelpLinkCatalogEntry = {
  id: HelpSectionId;
  label: string;
};

export type HelpLinkRange = {
  start: number;
  end: number;
  id: HelpSectionId;
  text: string;
};

function escapeRegExp(value: string): string {
  return value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}

/** Каталог подписей → id, длинные первыми. */
export function buildHelpLinkCatalog(getTitle: (id: HelpSectionId) => string): HelpLinkCatalogEntry[] {
  const byLabel = new Map<string, HelpSectionId>();
  for (const id of HELP_SECTION_IDS) {
    const title = getTitle(id).trim();
    if (title) byLabel.set(title, id);
    for (const alias of HELP_SECTION_LINK_ALIASES[id] ?? []) {
      const a = alias.trim();
      if (a) byLabel.set(a, id);
    }
  }
  return [...byLabel.entries()]
    .map(([label, id]) => ({ id, label }))
    .sort((a, b) => b.label.length - a.label.length || a.label.localeCompare(b.label));
}

function isBoundaryChar(ch: string | undefined): boolean {
  if (ch === undefined) return true;
  if (/^[\p{L}\p{N}]$/u.test(ch)) return false;
  return true;
}

function collectMatches(text: string, label: string, id: HelpSectionId): HelpLinkRange[] {
  const out: HelpLinkRange[] = [];
  if (!label) return out;

  const quoted = new RegExp(`«${escapeRegExp(label)}»`, 'g');
  for (const m of text.matchAll(quoted)) {
    if (m.index === undefined) continue;
    out.push({ start: m.index, end: m.index + m[0].length, id, text: m[0] });
  }

  const bare = new RegExp(escapeRegExp(label), 'g');
  for (const m of text.matchAll(bare)) {
    if (m.index === undefined) continue;
    const start = m.index;
    const end = start + m[0].length;
    const before = text[start - 1];
    const after = text[end];
    if (!isBoundaryChar(before) || !isBoundaryChar(after)) continue;
    if (before === '«' && after === '»') continue;
    out.push({ start, end, id, text: m[0] });
  }
  return out;
}

export function findHelpLinkRanges(text: string, catalog: readonly HelpLinkCatalogEntry[]): HelpLinkRange[] {
  const candidates: HelpLinkRange[] = [];
  for (const entry of catalog) {
    candidates.push(...collectMatches(text, entry.label, entry.id));
  }
  candidates.sort(
    (a, b) => a.start - b.start || b.end - b.start - (a.end - a.start),
  );

  const selected: HelpLinkRange[] = [];
  let cursor = 0;
  for (const range of candidates) {
    if (range.start < cursor) continue;
    selected.push(range);
    cursor = range.end;
  }
  return selected;
}

export function splitHelpTextWithLinks(
  text: string,
  catalog: readonly HelpLinkCatalogEntry[],
): Array<{ type: 'text'; value: string } | { type: 'link'; id: HelpSectionId; value: string }> {
  const ranges = findHelpLinkRanges(text, catalog);
  if (ranges.length === 0) return [{ type: 'text', value: text }];
  const parts: Array<{ type: 'text'; value: string } | { type: 'link'; id: HelpSectionId; value: string }> =
    [];
  let cursor = 0;
  for (const range of ranges) {
    if (range.start > cursor) {
      parts.push({ type: 'text', value: text.slice(cursor, range.start) });
    }
    parts.push({ type: 'link', id: range.id, value: range.text });
    cursor = range.end;
  }
  if (cursor < text.length) {
    parts.push({ type: 'text', value: text.slice(cursor) });
  }
  return parts;
}
