/**
 * Preview-Placeholder-Substitution für die Standalone-Tab-Vorschau.
 *
 * Im Send-Pfad (Worker) werden Platzhalter pro Empfänger ersetzt — beim
 * Vorschau-Tab gibt es aber (a) entweder einen echten Recipient aus dem
 * geladenen RecipientPicker, (b) oder gar keinen, dann fallen wir auf
 * fiktive Defaults zurück, damit kein `{{…}}`-Token mehr sichtbar ist.
 *
 * Diese Substitution nutzt die geteilten Helper aus `tag-substitution.ts`,
 * damit das Render-Verhalten zwischen Preview und Worker bit-genau identisch
 * bleibt (gleiche Whitespace-Toleranz, gleiches HTML-Escape).
 */

import { substituteTagsHtml } from '@/modules/sending/lib/tag-substitution';

export interface PreviewSampleRecipient {
  /** Vorname — fallback auf 'Max' wenn leer/null. */
  firstName?: string | null;
  lastName?: string | null;
  email?: string | null;
  crmId?: string | null;
  recipientId?: string | null;
  /** Frei formatierte CRM-Spalten — werden 1:1 gegen `{{KEY}}`-Tokens substituiert. */
  customData?: Record<string, unknown> | null;
}

export interface PreviewBrandContext {
  name: string;
  logoUrl?: string | null;
  imprintUrl?: string | null;
  privacyUrl?: string | null;
  shopDomain?: string | null;
}

export interface PreviewBriefingContext {
  ctaPrimaryUrl?: string | null;
  ctaSecondaryUrl?: string | null;
  heroUrl?: string | null;
}

export interface ApplyPreviewPlaceholdersOptions {
  recipient?: PreviewSampleRecipient | null;
  workspace?: PreviewBrandContext | null;
  briefing?: PreviewBriefingContext | null;
}

const FICTIONAL_DEFAULTS = {
  FIRST_NAME: 'Max',
  LAST_NAME: 'Mustermann',
  EMAIL: 'max.mustermann@example.com',
  RECIPIENT_ID: 'preview-sample',
  CRM_ID: 'PRV-000-001',
  HERO_URL: 'https://placehold.co/600x320/eef2f7/64748b?text=Hero-Bild',
  CTA_PRIMARY_URL: '#preview-cta-primary',
  CTA_SECONDARY_URL: '#preview-cta-secondary',
  LOGIN_LINK: '#preview-login',
  UNSUBSCRIBE_URL: '#preview-unsubscribe',
  BROWSER_URL: '#preview-browser',
  IMPRINT_URL: '#preview-imprint',
  PRIVACY_URL: '#preview-privacy',
  LOGO_URL: '',
  BRAND_NAME: '',
} as const;

function trimOrNull(s: string | null | undefined): string | null {
  if (s == null) return null;
  const t = String(s).trim();
  return t.length > 0 ? t : null;
}

/**
 * Baut den finalen Tag-Set: System-Defaults + briefingscontextspezifische
 * URLs + (optional) echte Recipient-Daten + (optional) custom-CRM-Spalten.
 *
 * Reihenfolge ist wichtig — späterer Layer überschreibt frühere:
 *   1. Fictional defaults
 *   2. Workspace-/Briefing-URLs (überschreiben hero/cta-defaults wenn gesetzt)
 *   3. Echter Recipient (überschreibt Max Mustermann wenn vorhanden)
 *   4. customData (CRM-Spalten — kollidiert nie mit System-Tags weil UPPER_SNAKE)
 */
function buildTagSet(opts: ApplyPreviewPlaceholdersOptions): Record<string, unknown> {
  const tags: Record<string, unknown> = { ...FICTIONAL_DEFAULTS };

  if (opts.workspace) {
    if (opts.workspace.name) tags.BRAND_NAME = opts.workspace.name;
    const logo = trimOrNull(opts.workspace.logoUrl);
    if (logo) tags.LOGO_URL = logo;
    const imprint = trimOrNull(opts.workspace.imprintUrl);
    if (imprint) tags.IMPRINT_URL = imprint;
    const privacy = trimOrNull(opts.workspace.privacyUrl);
    if (privacy) tags.PRIVACY_URL = privacy;
  }

  if (opts.briefing) {
    const ctaPrimary = trimOrNull(opts.briefing.ctaPrimaryUrl);
    if (ctaPrimary) tags.CTA_PRIMARY_URL = ctaPrimary;
    const ctaSecondary = trimOrNull(opts.briefing.ctaSecondaryUrl);
    if (ctaSecondary) tags.CTA_SECONDARY_URL = ctaSecondary;
    const hero = trimOrNull(opts.briefing.heroUrl);
    if (hero) tags.HERO_URL = hero;
  }

  if (opts.recipient) {
    const fn = trimOrNull(opts.recipient.firstName);
    if (fn) tags.FIRST_NAME = fn;
    const ln = trimOrNull(opts.recipient.lastName);
    if (ln) tags.LAST_NAME = ln;
    const email = trimOrNull(opts.recipient.email);
    if (email) tags.EMAIL = email;
    const crm = trimOrNull(opts.recipient.crmId);
    if (crm) tags.CRM_ID = crm;
    const rid = trimOrNull(opts.recipient.recipientId);
    if (rid) tags.RECIPIENT_ID = rid;

    if (opts.recipient.customData) {
      for (const [k, v] of Object.entries(opts.recipient.customData)) {
        // System-Defaults nicht überschreiben — gleiches Verhalten wie im Worker
        if (k in tags) continue;
        tags[k] = v;
      }
    }
  }

  return tags;
}

/**
 * Wendet alle Platzhalter auf einen HTML-Body an. Nicht-bekannte `{{KEY}}`-Tokens
 * bleiben stehen wenn sie weder in System-Defaults noch in customData vorkommen —
 * der Aufrufer kann optional einen zusätzlichen Sweep mit `stripUnknownTags=true`
 * machen, dann werden alle übriggebliebenen Tokens zu Leerstring.
 */
export function applyPreviewPlaceholders(
  html: string,
  opts: ApplyPreviewPlaceholdersOptions = {},
  options: { stripUnknownTags?: boolean } = {},
): string {
  const tags = buildTagSet(opts);
  let out = substituteTagsHtml(html, tags);
  if (options.stripUnknownTags) {
    out = out.replace(/\{\{\s*[A-Za-z0-9_.\-()]+\s*\}\}/g, '');
  }
  return out;
}
