/**
 * Konvertiert strukturierte Brief-Sections (Output von draftBrief) in TipTap-JSON-Doc + HTML + Plain-Text.
 * Pure Function — kein LLM-Call, keine externen Abhängigkeiten außer dem TipTap-JSON-Format.
 *
 * Doc-Struktur passt zu den StarterKit-Extensions in MarketingEditor.tsx (heading l2/l3,
 * paragraph, bulletList/listItem, mark.italic, mark.bold). Die HTML-Serialisierung ist bewusst
 * minimal gehalten und matcht TipTap's Default-Output 1:1, sodass Suggest-/Auto-Save-Roundtrips
 * stabil bleiben.
 */

export interface BriefSections {
  headline: string;
  intro: string;
  pain_point: string;
  solution: string;
  benefits: string[];
  cta_paragraph: string;
  ps_line?: string;
  signature: string;
}

export type Lang = 'de' | 'en';

interface SectionLabels {
  problem: string;
  offering: string;
  benefits: string;
}

const LABELS: Record<Lang, SectionLabels> = {
  de: { problem: 'Das Problem', offering: 'Unser Angebot', benefits: 'Was Sie davon haben' },
  en: { problem: 'The problem', offering: 'What we offer', benefits: 'What you get' },
};

interface TipTapNode {
  type: string;
  attrs?: Record<string, unknown>;
  content?: TipTapNode[];
  marks?: Array<{ type: string; attrs?: Record<string, unknown> }>;
  text?: string;
}

interface TipTapDoc {
  type: 'doc';
  content: TipTapNode[];
}

const p = (text: string, marks?: Array<{ type: string }>): TipTapNode => ({
  type: 'paragraph',
  content: text ? [{ type: 'text', text, ...(marks ? { marks } : {}) }] : [],
});

const heading = (level: 2 | 3, text: string): TipTapNode => ({
  type: 'heading',
  attrs: { level },
  content: [{ type: 'text', text }],
});

const bulletList = (items: string[]): TipTapNode => ({
  type: 'bulletList',
  content: items
    .filter((s) => s && s.trim())
    .map((item) => ({
      type: 'listItem',
      content: [{ type: 'paragraph', content: [{ type: 'text', text: item.trim() }] }],
    })),
});

export interface TipTapResult {
  json: TipTapDoc;
  html: string;
  text: string;
}

export function sectionsToTiptap(sections: BriefSections, lang: Lang = 'de'): TipTapResult {
  const labels = LABELS[lang];
  const nodes: TipTapNode[] = [];

  if (sections.headline?.trim()) nodes.push(heading(2, sections.headline.trim()));
  if (sections.intro?.trim()) nodes.push(p(sections.intro.trim()));

  if (sections.pain_point?.trim()) {
    nodes.push(heading(3, labels.problem));
    nodes.push(p(sections.pain_point.trim()));
  }

  if (sections.solution?.trim()) {
    nodes.push(heading(3, labels.offering));
    nodes.push(p(sections.solution.trim()));
  }

  const cleanBenefits = (sections.benefits ?? []).map((b) => b?.trim()).filter((b): b is string => !!b && b.length > 0);
  if (cleanBenefits.length > 0) {
    nodes.push(heading(3, labels.benefits));
    nodes.push(bulletList(cleanBenefits));
  }

  if (sections.cta_paragraph?.trim()) nodes.push(p(sections.cta_paragraph.trim(), [{ type: 'bold' }]));

  if (sections.ps_line?.trim()) nodes.push(p(sections.ps_line.trim(), [{ type: 'italic' }]));

  if (sections.signature?.trim()) nodes.push(p(sections.signature.trim()));

  const json: TipTapDoc = { type: 'doc', content: nodes };
  return { json, html: docToHtml(json), text: docToText(json) };
}

function escapeHtml(s: string): string {
  return s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
}

function nodeToHtml(node: TipTapNode): string {
  if (node.type === 'text') {
    let html = escapeHtml(node.text ?? '');
    for (const mark of node.marks ?? []) {
      if (mark.type === 'bold') html = `<strong>${html}</strong>`;
      else if (mark.type === 'italic') html = `<em>${html}</em>`;
      else if (mark.type === 'underline') html = `<u>${html}</u>`;
    }
    return html;
  }
  const children = (node.content ?? []).map(nodeToHtml).join('');
  switch (node.type) {
    case 'heading': {
      const lvl = (node.attrs?.level as number) ?? 2;
      return `<h${lvl}>${children}</h${lvl}>`;
    }
    case 'paragraph':
      return `<p>${children}</p>`;
    case 'bulletList':
      return `<ul>${children}</ul>`;
    case 'orderedList':
      return `<ol>${children}</ol>`;
    case 'listItem':
      return `<li>${children}</li>`;
    default:
      return children;
  }
}

/**
 * Konvertiert ein TipTap-JSON-Doc zu inline-HTML. Wird von `inject-sections.ts`
 * gebraucht, um den User-edited Content einer BriefingSectionInstance ins
 * `{{TIPTAP_HTML}}`-Slot eines Section-Templates zu rendern.
 */
export function docToHtml(doc: TipTapDoc): string {
  return doc.content.map(nodeToHtml).join('');
}

export type { TipTapDoc, TipTapNode };

function nodeToText(node: TipTapNode): string {
  if (node.type === 'text') return node.text ?? '';
  const children = (node.content ?? []).map(nodeToText).join('');
  if (node.type === 'paragraph' || node.type === 'heading' || node.type === 'listItem') return `${children}\n`;
  return children;
}

function docToText(doc: TipTapDoc): string {
  return doc.content.map(nodeToText).join('').trim();
}
