import type { Mention } from './mentions';
import { linkSpans } from './urls';

export type InlineSegment =
  | { kind: 'text'; text: string }
  | { kind: 'mention'; text: string; user_id: string }
  | { kind: 'link'; text: string; href: string };

interface Span {
  start: number;
  end: number;
  segment: InlineSegment;
}

const WORD_CHAR = /[\p{L}\p{N}_]/u;

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

function mentionSpans(text: string, mentions: Mention[], taken: Span[]): Span[] {
  const byText = new Map(mentions.filter((m) => m.text).map((m) => [m.text, m.user_id]));
  if (byText.size === 0) return [];
  const names = [...byText.keys()].sort((a, b) => b.length - a.length);
  const out: Span[] = [];
  for (const m of text.matchAll(new RegExp(names.map(escapeRegExp).join('|'), 'g'))) {
    const start = m.index;
    const end = start + m[0].length;
    if (WORD_CHAR.test(text[start - 1] ?? '') || WORD_CHAR.test(text[end] ?? '')) continue;
    if (taken.some((s) => start < s.end && end > s.start)) continue;
    out.push({ start, end, segment: { kind: 'mention', text: m[0], user_id: byText.get(m[0])! } });
  }
  return out;
}

export function segmentInline(text: string, mentions: Mention[]): InlineSegment[] {
  const links: Span[] = linkSpans(text).map((l) => ({
    start: l.start,
    end: l.end,
    segment: { kind: 'link', text: text.slice(l.start, l.end), href: l.href }
  }));
  const spans = [...links, ...mentionSpans(text, mentions, links)].sort((a, b) => a.start - b.start);
  const out: InlineSegment[] = [];
  let last = 0;
  for (const s of spans) {
    if (s.start > last) out.push({ kind: 'text', text: text.slice(last, s.start) });
    out.push(s.segment);
    last = s.end;
  }
  if (last < text.length) out.push({ kind: 'text', text: text.slice(last) });
  return out;
}
