'use client';

import { useEffect, useState } from 'react';
import { X, Plus, Trash2, Save, Loader2, RotateCcw, Palette, Type, Sparkles, Building2, MousePointerClick, AlertTriangle, RefreshCw, Webhook, Eye, EyeOff, BarChart3, Key, Globe, Copy, Check, BookOpen, Send } from 'lucide-react';
import { cn } from '@/lib/utils';
import { TriggerTemplatesPanel } from './TriggerTemplatesPanel';
import { ShopIntegrationModal } from './ShopIntegrationModal';
import { M365SendersPoolTab } from './M365SendersPoolTab';

type TabName = 'workspaces' | 'delivery' | 'prompts' | 'conversions' | 'triggers' | 'onsite';

interface BrandKit {
  version: number;
  header?: { phone?: string; tagline?: string };
  footer?: {
    mode?: 'structured' | 'mjml';
    customMjml?: string;
    legalFooterText?: string;
    legalFooterTextEn?: string;
    confidentialityNotice?: string;
    confidentialityNoticeEn?: string;
    showUnsubscribe?: boolean;
    companyInfo?: string;
    legalRegulations?: string;
    complaintBodies?: string;
    defaultSignature?: string;
    defaultSignatureEn?: string;
  };
}

interface Workspace {
  id: string;
  slug: string;
  name: string;
  primaryColor: string;
  secondaryColor?: string | null;
  logoUrl?: string | null;
  senderDomain: string;
  senderName: string;
  senderEmail: string;
  replyToEmail: string;
  footerText: string;
  brandVoice: string;
  wordingStyle?: string | null;
  designStyle?: string | null;
  companyId?: number | null;
  /**
   * Ziel-Shop-Domain für Login-Direktlinks (Kompass-Magic-Links).
   * Optional — Workspaces ohne Shop produzieren leere `{{LOGIN_LINK}}`-Substitution.
   */
  shopDomain?: string | null;
  imprintUrl: string;
  privacyUrl: string;
  brandKitJson?: BrandKit | null;
  brandKit?: BrandKit;  // optionaler client-only mirror für POST
  /** Phase 3: Per-Workspace Email-Attribution-Settings. */
  attributionModel?: 'last-click' | 'first-click' | 'linear' | 'time-decay';
  attributionLookbackDays?: number;
  webhookSecret?: string | null;
  ga4PropertyId?: string | null;
  cumasRecipientField?: string | null;
  activeConversionKinds?: Array<'order' | 'lead' | 'magic_login' | 'form_submit'>;
}

interface SettingsBundle {
  systemPromptGenerate: string;
  systemPromptSuggest: string;
  systemPromptImage: string;
}

export interface SettingsDrawerProps {
  open: boolean;
  onClose: () => void;
  // Callback wenn Briefing-Panel neue Workspaces laden soll. `savedSlug` zeigt an, welche Workspace
  // gerade gespeichert wurde — die page.tsx nutzt das, um bei Edit der aktiven Workspace einen
  // automatischen Re-Render der Live-Preview zu triggern (Header/Footer-Änderungen).
  onBrandsChanged?: (savedSlug?: string) => void;
  /** Nach Speichern des M365-Sender-Pools — Parent sollte `/api/m365/senders` neu laden. */
  onM365SendersPoolSaved?: () => void;
}

export function SettingsDrawer({ open, onClose, onBrandsChanged, onM365SendersPoolSaved }: SettingsDrawerProps) {
  const [activeTab, setActiveTab] = useState<TabName>('workspaces');
  const [workspaces, setBrands] = useState<Workspace[] | null>(null);
  const [settings, setSettings] = useState<SettingsBundle | null>(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    if (!open) return;
    setLoading(true);
    Promise.all([
      fetch('/api/workspaces').then(r => r.json()),
      fetch('/api/settings').then(r => r.json()),
    ]).then(([brandsData, settingsData]) => {
      setBrands(brandsData.workspaces ?? []);
      setSettings(settingsData);
      setLoading(false);
    });
  }, [open]);

  if (!open) return null;

  return (
    <>
      {/* Backdrop */}
      <div className="fixed inset-0 z-40 bg-black/40 backdrop-blur-sm" onClick={onClose} />

      {/* Drawer */}
      <aside className="fixed right-0 top-0 z-50 flex h-full w-full max-w-[680px] flex-col border-l border-zinc-200 bg-white shadow-2xl dark:border-zinc-800 dark:bg-zinc-950">
        <header className="flex items-center justify-between border-b border-zinc-200 px-6 py-4 dark:border-zinc-800">
          <div>
            <h2 className="text-base font-semibold">Einstellungen</h2>
            <p className="text-xs text-zinc-500">Workspaces, M365-Versand, KI-Prompts und Tracking</p>
          </div>
          <button onClick={onClose} className="rounded-md p-1.5 text-zinc-500 hover:bg-zinc-100 dark:hover:bg-zinc-800">
            <X className="h-4 w-4" />
          </button>
        </header>

        <nav className="flex flex-wrap border-b border-zinc-200 px-2 dark:border-zinc-800 sm:px-4">
          {(['workspaces', 'delivery', 'prompts', 'conversions', 'triggers', 'onsite'] as const).map(t => {
            const Icon =
              t === 'workspaces'
                ? Building2
                : t === 'delivery'
                  ? Send
                  : t === 'prompts'
                    ? Sparkles
                    : t === 'conversions'
                      ? MousePointerClick
                      : t === 'triggers'
                        ? Webhook
                        : Globe;
            const label =
              t === 'workspaces'
                ? 'Workspaces'
                : t === 'delivery'
                  ? 'M365 / Versand'
                  : t === 'prompts'
                    ? 'KI-Prompts'
                    : t === 'conversions'
                      ? 'Conversions'
                      : t === 'triggers'
                        ? 'Trigger'
                        : 'Onsite-Tracking';
            return (
              <button
                key={t}
                onClick={() => setActiveTab(t)}
                className={cn(
                  'inline-flex items-center gap-1.5 border-b-2 px-2 py-2.5 text-sm font-medium transition sm:px-3',
                  activeTab === t
                    ? 'border-zinc-900 text-zinc-900 dark:border-zinc-100 dark:text-zinc-100'
                    : 'border-transparent text-zinc-500 hover:text-zinc-700 dark:hover:text-zinc-300',
                )}
              >
                <Icon className="h-3.5 w-3.5" /> {label}
              </button>
            );
          })}
        </nav>

        <div className="flex-1 overflow-y-auto p-6">
          {loading && <div className="flex items-center gap-2 text-sm text-zinc-500"><Loader2 className="h-4 w-4 animate-spin" /> Lade …</div>}
          {!loading && activeTab === 'workspaces' && workspaces && (
            <BrandsTab workspaces={workspaces} onSaved={(slug) => {
              fetch('/api/workspaces').then(r => r.json()).then(d => setBrands(d.workspaces));
              onBrandsChanged?.(slug);
            }} />
          )}
          {activeTab === 'delivery' && (
            <M365SendersPoolTab onSaved={() => onM365SendersPoolSaved?.()} />
          )}
          {!loading && activeTab === 'prompts' && settings && (
            <PromptsTab settings={settings} onSave={async (patch) => {
              const res = await fetch('/api/settings', { method: 'PATCH', headers: { 'content-type': 'application/json' }, body: JSON.stringify(patch) });
              if (res.ok) setSettings(await res.json());
            }} />
          )}
          {!loading && activeTab === 'conversions' && (
            <ConversionsTab />
          )}
          {/* Triggers-Tab läuft eigenständig — kein Workspaces/Settings-Load nötig, eigener Fetch im Panel. */}
          {activeTab === 'triggers' && (
            <TriggerTemplatesPanel />
          )}
          {/* Onsite-Tracking-Tab (Phase 3+4): pro Workspace Webhook-Secret-Rotation,
              GA4-Property + Service-Account, mf-track.js Snippet-Generator. */}
          {!loading && activeTab === 'onsite' && workspaces && (
            <OnsiteTrackingTab
              workspaces={workspaces}
              onSaved={() => {
                fetch('/api/workspaces').then(r => r.json()).then(d => setBrands(d.workspaces));
              }}
            />
          )}
        </div>
      </aside>
    </>
  );
}

// ─── Onsite-Tracking-Tab (Phase 3+4) ────────────────────────────────────────

function OnsiteTrackingTab({ workspaces, onSaved }: { workspaces: Workspace[]; onSaved: () => void }) {
  return (
    <div className="flex flex-col gap-4">
      <div className="rounded-md border border-blue-200 bg-blue-50 px-3 py-2 text-xs text-blue-900 dark:border-blue-900/50 dark:bg-blue-950/30 dark:text-blue-200">
        <strong>Wie funktioniert das?</strong> Pro Workspace kann ein mf-track.js-Snippet auf der Zielseite eingebunden werden,
        ein Webhook-Empfänger für Shop-Push-Events aktiviert und eine GA4-Property für Session-Lookups verbunden werden.
        Alle drei sind unabhängig — du musst nicht alle aktivieren.
      </div>
      {workspaces.map((b) => (
        <BrandOnsiteCard key={b.id} workspace={b} onSaved={onSaved} />
      ))}
    </div>
  );
}

function BrandOnsiteCard({ workspace, onSaved }: { workspace: Workspace; onSaved: () => void }) {
  const [ga4PropertyId, setGa4PropertyId] = useState(workspace.ga4PropertyId ?? '');
  const [credentialsJson, setCredentialsJson] = useState('');
  const [savingProp, setSavingProp] = useState(false);
  const [rotatingSecret, setRotatingSecret] = useState(false);
  const [newSecret, setNewSecret] = useState<string | null>(null);
  const [feedback, setFeedback] = useState<string | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [copiedKey, setCopiedKey] = useState<string | null>(null);
  const [docOpen, setDocOpen] = useState(false);

  // Snippet generieren: Origin der MailForge-Instanz aus der aktuellen URL ableiten
  const snippet = `<script src="${typeof window !== 'undefined' ? window.location.origin : 'https://mailforge.example.de'}/mf-track.js" data-workspace="${workspace.slug}" defer></script>`;
  const webhookUrl = `${typeof window !== 'undefined' ? window.location.origin : 'https://mailforge.example.de'}/api/track/webhook/${workspace.slug}`;

  async function copyToClipboard(text: string, key: string) {
    try {
      await navigator.clipboard.writeText(text);
      setCopiedKey(key);
      setTimeout(() => setCopiedKey((cur) => (cur === key ? null : cur)), 2000);
    } catch {
      setError('Clipboard nicht verfügbar');
    }
  }

  async function saveGa4PropertyId() {
    setSavingProp(true);
    setError(null);
    try {
      // GA4-Property-ID läuft via /api/workspaces (upsertWorkspace) — gleicher Pfad wie andere Workspace-Felder
      const next = { ...workspace, ga4PropertyId: ga4PropertyId.trim() || null };
      const res = await fetch('/api/workspaces', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify(next),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      setFeedback('GA4-Property-ID gespeichert');
      onSaved();
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Speichern fehlgeschlagen');
    } finally {
      setSavingProp(false);
      setTimeout(() => setFeedback(null), 3000);
    }
  }

  async function uploadCredentials() {
    setError(null);
    let parsed: unknown;
    try {
      parsed = JSON.parse(credentialsJson);
    } catch {
      setError('Ungültiges JSON — bitte den vollständigen Service-Account-Download von Google Cloud einfügen');
      return;
    }
    try {
      const res = await fetch(`/api/workspaces/${workspace.slug}/credentials`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ ga4CredentialsJson: parsed }),
      });
      const json = await res.json();
      if (!res.ok) throw new Error(json.error ?? `HTTP ${res.status}`);
      setFeedback('GA4-Credentials gespeichert');
      setCredentialsJson('');
      onSaved();
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Upload fehlgeschlagen');
    } finally {
      setTimeout(() => setFeedback(null), 3000);
    }
  }

  async function clearCredentials() {
    if (!confirm('GA4-Credentials wirklich löschen? Session-Lookups funktionieren danach nicht mehr.')) return;
    try {
      const res = await fetch(`/api/workspaces/${workspace.slug}/credentials`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ ga4CredentialsJson: null }),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      setFeedback('Credentials gelöscht');
      onSaved();
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Löschen fehlgeschlagen');
    } finally {
      setTimeout(() => setFeedback(null), 3000);
    }
  }

  async function rotateWebhookSecret() {
    if (!confirm(`Neues Webhook-Secret für ${workspace.name} generieren?\n\nDer alte Wert wird SOFORT ungültig — Shop-Backends müssen synchron umgestellt werden.`)) return;
    setRotatingSecret(true);
    setError(null);
    try {
      const res = await fetch(`/api/workspaces/${workspace.slug}/credentials`, {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({ rotateWebhookSecret: true }),
      });
      const json = await res.json();
      if (!res.ok) throw new Error(json.error ?? `HTTP ${res.status}`);
      setNewSecret(json.webhookSecret);
      setFeedback('Webhook-Secret rotiert — speichere ihn jetzt, danach nicht mehr abrufbar!');
      onSaved();
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Rotation fehlgeschlagen');
    } finally {
      setRotatingSecret(false);
    }
  }

  const hasCredentials = !!workspace.ga4PropertyId;
  // Note: wir wissen nur, dass ga4PropertyId gesetzt ist; ga4CredentialsJson kommt nicht ans Frontend zurück (sensitiv).

  return (
    <div className="rounded-lg border border-zinc-200 bg-white dark:border-zinc-800 dark:bg-zinc-900">
      <div className="flex items-center justify-between border-b border-zinc-200 px-4 py-3 dark:border-zinc-800">
        <div className="flex items-center gap-2">
          <span className="h-3 w-3 rounded-full" style={{ backgroundColor: workspace.primaryColor }} />
          <h3 className="text-sm font-semibold text-zinc-900 dark:text-zinc-100">{workspace.name}</h3>
          <span className="text-[10px] uppercase tracking-wider text-zinc-500">{workspace.slug}</span>
        </div>
        <button
          type="button"
          onClick={() => setDocOpen(true)}
          className="inline-flex items-center gap-1.5 rounded-md border border-zinc-200 bg-white px-2 py-1 text-[11px] font-medium text-zinc-700 transition hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800"
          title="Quick-Reference für den Shop-Entwickler"
        >
          <BookOpen className="h-3.5 w-3.5" />
          Anleitung
        </button>
      </div>

      <ShopIntegrationModal
        open={docOpen}
        onClose={() => setDocOpen(false)}
        workspaceSlug={workspace.slug}
        brandName={workspace.name}
      />

      <div className="space-y-5 p-4">
        {/* ─── mf-track.js Snippet ─── */}
        <section>
          <div className="flex items-center gap-1.5 text-xs font-semibold text-zinc-700 dark:text-zinc-300">
            <Globe className="h-3.5 w-3.5" />
            Onsite-Snippet
          </div>
          <p className="mt-0.5 text-[11px] text-zinc-500">
            Einbinden auf {workspace.shopDomain ? <code>{workspace.shopDomain}</code> : 'der Workspace-Zielseite'} vor <code>&lt;/body&gt;</code>.
          </p>
          <div className="mt-2 flex items-stretch gap-2">
            <code className="flex-1 overflow-x-auto rounded border border-zinc-200 bg-zinc-50 px-2 py-1.5 font-mono text-[10px] text-zinc-700 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-300">
              {snippet}
            </code>
            <button
              type="button"
              onClick={() => void copyToClipboard(snippet, 'snippet')}
              className="inline-flex items-center gap-1 rounded border border-zinc-200 bg-white px-2 text-[11px] hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:hover:bg-zinc-800"
            >
              {copiedKey === 'snippet' ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
              Kopieren
            </button>
          </div>
        </section>

        {/* ─── Webhook ─── */}
        <section>
          <div className="flex items-center gap-1.5 text-xs font-semibold text-zinc-700 dark:text-zinc-300">
            <Webhook className="h-3.5 w-3.5" />
            Webhook-Endpoint
          </div>
          <p className="mt-0.5 text-[11px] text-zinc-500">
            HMAC-SHA256 Signatur im Header <code>X-MailForge-Signature: sha256=&lt;hex&gt;</code>.
          </p>
          <div className="mt-2 flex items-stretch gap-2">
            <code className="flex-1 overflow-x-auto rounded border border-zinc-200 bg-zinc-50 px-2 py-1.5 font-mono text-[10px] text-zinc-700 dark:border-zinc-700 dark:bg-zinc-950 dark:text-zinc-300">
              POST {webhookUrl}
            </code>
            <button
              type="button"
              onClick={() => void copyToClipboard(webhookUrl, 'webhook-url')}
              className="inline-flex items-center gap-1 rounded border border-zinc-200 bg-white px-2 text-[11px] hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:hover:bg-zinc-800"
            >
              {copiedKey === 'webhook-url' ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
              URL
            </button>
          </div>
          <div className="mt-2 flex items-center gap-2 text-xs">
            <span className="text-zinc-500">Secret:</span>
            <span className="flex-1 truncate font-mono text-[11px]">
              {newSecret ?? (workspace.webhookSecret ? `${workspace.webhookSecret.slice(0, 10)}…${workspace.webhookSecret.slice(-4)}` : 'nicht konfiguriert')}
            </span>
            {newSecret && (
              <button
                type="button"
                onClick={() => void copyToClipboard(newSecret, 'secret')}
                className="inline-flex items-center gap-1 rounded border border-zinc-200 bg-white px-2 py-1 text-[11px] hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:hover:bg-zinc-800"
              >
                {copiedKey === 'secret' ? <Check className="h-3 w-3" /> : <Copy className="h-3 w-3" />}
                Kopieren
              </button>
            )}
            <button
              type="button"
              onClick={() => void rotateWebhookSecret()}
              disabled={rotatingSecret}
              className="inline-flex items-center gap-1 rounded border border-zinc-200 bg-white px-2 py-1 text-[11px] hover:bg-zinc-50 disabled:opacity-50 dark:border-zinc-700 dark:bg-zinc-900 dark:hover:bg-zinc-800"
            >
              {rotatingSecret ? <Loader2 className="h-3 w-3 animate-spin" /> : <RefreshCw className="h-3 w-3" />}
              {workspace.webhookSecret ? 'Rotieren' : 'Generieren'}
            </button>
          </div>
        </section>

        {/* ─── GA4 ─── */}
        <section>
          <div className="flex items-center gap-1.5 text-xs font-semibold text-zinc-700 dark:text-zinc-300">
            <BarChart3 className="h-3.5 w-3.5" />
            GA4-Quervalidierung
          </div>
          <p className="mt-0.5 text-[11px] text-zinc-500">
            On-Demand Session-Lookup im Recipient-Drawer. Property-ID + Service-Account-Credentials erforderlich.
          </p>
          <div className="mt-2 space-y-2">
            <label className="block">
              <span className="block text-[11px] text-zinc-500">GA4 Property-ID</span>
              <div className="mt-1 flex items-stretch gap-2">
                <input
                  type="text"
                  value={ga4PropertyId}
                  onChange={(e) => setGa4PropertyId(e.target.value)}
                  placeholder="z.B. 123456789"
                  className="flex-1 rounded border border-zinc-200 bg-white px-2 py-1.5 text-xs font-mono dark:border-zinc-700 dark:bg-zinc-950"
                />
                <button
                  type="button"
                  onClick={() => void saveGa4PropertyId()}
                  disabled={savingProp}
                  className="inline-flex items-center gap-1 rounded bg-zinc-900 px-3 py-1 text-[11px] text-white hover:bg-zinc-800 disabled:opacity-50 dark:bg-zinc-100 dark:text-zinc-900 dark:hover:bg-zinc-200"
                >
                  {savingProp ? <Loader2 className="h-3 w-3 animate-spin" /> : <Save className="h-3 w-3" />}
                  Speichern
                </button>
              </div>
            </label>

            <label className="block">
              <span className="flex items-center justify-between text-[11px] text-zinc-500">
                <span>Service-Account JSON {hasCredentials && <span className="text-emerald-600 dark:text-emerald-400">✓ konfiguriert</span>}</span>
                {hasCredentials && (
                  <button type="button" onClick={() => void clearCredentials()} className="text-[10px] text-red-600 hover:underline">
                    Löschen
                  </button>
                )}
              </span>
              <textarea
                value={credentialsJson}
                onChange={(e) => setCredentialsJson(e.target.value)}
                placeholder='{"client_email": "...", "private_key": "-----BEGIN PRIVATE KEY-----..."}'
                rows={4}
                className="mt-1 w-full rounded border border-zinc-200 bg-white p-2 font-mono text-[10px] dark:border-zinc-700 dark:bg-zinc-950"
              />
              {credentialsJson && (
                <button
                  type="button"
                  onClick={() => void uploadCredentials()}
                  className="mt-1 inline-flex items-center gap-1 rounded bg-zinc-900 px-3 py-1 text-[11px] text-white hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900"
                >
                  <Save className="h-3 w-3" /> Credentials speichern
                </button>
              )}
            </label>
          </div>
        </section>

        {feedback && (
          <div className="rounded-md border border-emerald-200 bg-emerald-50 px-3 py-1.5 text-[11px] text-emerald-800 dark:border-emerald-900/50 dark:bg-emerald-950/30">
            {feedback}
          </div>
        )}
        {error && (
          <div className="flex items-start gap-1.5 rounded-md border border-red-200 bg-red-50 px-3 py-1.5 text-[11px] text-red-800 dark:border-red-900/50 dark:bg-red-950/30">
            <AlertTriangle className="h-3.5 w-3.5 mt-0.5" />
            {error}
          </div>
        )}
      </div>
    </div>
  );
}

// ----- Conversions-Tab (Phase 3b: Cumas/Nova-API-Polling) -------------------

interface ConversionPollingState {
  enabled: boolean;
  intervalMinutes: number;
  sources: Array<'cumas_orderPrivateShop' | 'cumas_evb'>;
  lastPolledAt?: Partial<Record<'cumas_orderPrivateShop' | 'cumas_evb', string>>;
  /** Pro Quelle der Cumas-Feldname (Dot-Path) der die Recipient-ID trägt. */
  recipientIdField?: Partial<Record<'cumas_orderPrivateShop' | 'cumas_evb', string>>;
}

function ConversionsTab() {
  const [state, setState] = useState<ConversionPollingState | null>(null);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [savedAt, setSavedAt] = useState<number | null>(null);

  useEffect(() => {
    fetch('/api/settings/conversion-polling')
      .then(r => r.json())
      .then((d: ConversionPollingState) => setState(d))
      .catch(e => setError(e instanceof Error ? e.message : 'Lookup failed'));
  }, []);

  const update = (patch: Partial<ConversionPollingState>) => {
    setState(prev => prev ? { ...prev, ...patch } : prev);
  };

  const save = async (extra?: { resetLastPolledAt?: boolean }) => {
    if (!state) return;
    setSaving(true);
    setError(null);
    try {
      const res = await fetch('/api/settings/conversion-polling', {
        method: 'PATCH',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({
          enabled: state.enabled,
          intervalMinutes: state.intervalMinutes,
          sources: state.sources,
          recipientIdField: state.recipientIdField ?? {},
          ...extra,
        }),
      });
      if (!res.ok) throw new Error(`HTTP ${res.status}`);
      const next: ConversionPollingState = await res.json();
      setState(next);
      setSavedAt(Date.now());
    } catch (e) {
      setError(e instanceof Error ? e.message : 'Save failed');
    } finally {
      setSaving(false);
    }
  };

  if (!state) {
    return (
      <div className="flex items-center gap-2 text-sm text-zinc-500">
        <Loader2 className="h-4 w-4 animate-spin" /> Lade Polling-Settings …
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-6 text-sm">
      <div>
        <h3 className="text-base font-semibold text-zinc-900 dark:text-zinc-100">Conversion-Tracking</h3>
        <p className="mt-1 text-xs leading-relaxed text-zinc-600 dark:text-zinc-400">
          Verfolge Conversions auf zwei Wegen: <strong>Pixel</strong> (URL-Parameter auf der Thank-You-Page,
          immer aktiv via <code className="rounded bg-zinc-100 px-1 py-0.5 text-[10px] dark:bg-zinc-800">/api/track/conversion</code>)
          und optional <strong>API-Polling</strong> (regelmäßiger Cumas/Nova-Sync, Match per Email).
        </p>
      </div>

      {/* ─── Pixel-Hinweis (immer-an) ──────────────────────────────────── */}
      <div className="rounded-lg border border-emerald-200 bg-emerald-50 p-4 dark:border-emerald-900/50 dark:bg-emerald-950/30">
        <div className="flex items-center gap-2 text-xs font-semibold text-emerald-900 dark:text-emerald-200">
          <MousePointerClick className="h-3.5 w-3.5" /> Conversion-Pixel (Default, immer aktiv)
        </div>
        <p className="mt-2 text-[11px] leading-relaxed text-emerald-900/80 dark:text-emerald-200/80">
          Integriere dieses Snippet auf der Thank-You-Page (z.B. kompass-versicherung.de/vielen-dank-fuer-ihr-interesse):
        </p>
        <pre className="mt-2 overflow-x-auto rounded-md bg-white/80 p-2 text-[10px] leading-tight text-emerald-900 dark:bg-emerald-950/50 dark:text-emerald-200">
{`<script>
  const u = new URL(location.href);
  const r = u.searchParams.get('id');
  const part = u.searchParams.get('part') || '';
  if (r) {
    new Image().src =
      \`https://mailforge.example.de/api/track/conversion?r=\${encodeURIComponent(r)}\` +
      \`&part=\${encodeURIComponent(part)}&kind=form_submit\`;
  }
</script>`}
        </pre>
      </div>

      {/* ─── API-Polling (Toggle) ──────────────────────────────────────── */}
      <div className="rounded-lg border border-zinc-200 bg-white p-4 dark:border-zinc-700 dark:bg-zinc-900">
        <label className="flex items-start gap-3 cursor-pointer">
          <input
            type="checkbox"
            checked={state.enabled}
            onChange={e => update({ enabled: e.target.checked })}
            className="mt-0.5 h-4 w-4 rounded border-zinc-300"
          />
          <div className="flex-1">
            <div className="text-sm font-semibold text-zinc-900 dark:text-zinc-100">
              Cumas/Nova API-Polling aktivieren
            </div>
            <p className="mt-1 text-[11px] leading-relaxed text-zinc-600 dark:text-zinc-400">
              Worker pollt regelmäßig die Cumas-API auf neue Orders/eVBs und matcht sie per Email
              gegen versendete Recipients. Voraussetzung: <code>CRM_USERNAME</code> + <code>CRM_PASSWORD</code> in <code>.env.local</code>.
            </p>
          </div>
        </label>

        {state.enabled && (
          <div className="mt-4 space-y-3 border-t border-zinc-200 pt-4 dark:border-zinc-700">
            <FormField label="Polling-Intervall" hint="Minuten zwischen Polls. Min 1, Max 1440 (24h).">
              <input
                type="number"
                min={1}
                max={1440}
                value={state.intervalMinutes}
                onChange={e => update({ intervalMinutes: Math.max(1, Math.min(1440, parseInt(e.target.value, 10) || 15)) })}
                className="w-32 rounded-md border border-zinc-200 bg-white px-2.5 py-1.5 text-sm dark:border-zinc-700 dark:bg-zinc-900"
              />
            </FormField>

            <FormField label="Polling-Quellen" hint="Welche Cumas-Collections gepollt werden. Mehrfach-Auswahl möglich.">
              <div className="flex flex-col gap-1.5">
                {(['cumas_orderPrivateShop', 'cumas_evb'] as const).map(src => (
                  <label key={src} className="flex items-center gap-2 text-xs">
                    <input
                      type="checkbox"
                      checked={state.sources.includes(src)}
                      onChange={e => {
                        const next = e.target.checked
                          ? [...new Set([...state.sources, src])]
                          : state.sources.filter(s => s !== src);
                        update({ sources: next.length > 0 ? next : ['cumas_orderPrivateShop'] });
                      }}
                      className="h-3.5 w-3.5 rounded border-zinc-300"
                    />
                    <code className="text-[11px] text-zinc-700 dark:text-zinc-300">{src}</code>
                    {src === 'cumas_evb' && (
                      <span className="text-[10px] text-amber-600">⚠ eVB-Email-Lookup noch im Skeleton-Status</span>
                    )}
                  </label>
                ))}
              </div>
            </FormField>

            <FormField
              label="Cumas-Feldname für Recipient-ID"
              hint="Optional. Dot-Path im Order-Record (z.B. 'extra_data.mf_rcp' oder 'customer_note'). Wenn gesetzt, matched der Poller zuerst per Recipient-ID, dann per Email. Leer = nur Email-Match (wie bisher)."
            >
              <div className="flex flex-col gap-2">
                {state.sources.map(src => (
                  <div key={src} className="flex items-center gap-2">
                    <code className="w-44 shrink-0 text-[11px] text-zinc-500">{src}</code>
                    <input
                      type="text"
                      placeholder="z.B. extra_data.mf_rcp"
                      value={state.recipientIdField?.[src] ?? ''}
                      onChange={e => update({
                        recipientIdField: {
                          ...(state.recipientIdField ?? {}),
                          [src]: e.target.value,
                        },
                      })}
                      pattern="[A-Za-z0-9_.\-]*"
                      className="flex-1 rounded-md border border-zinc-200 bg-white px-2.5 py-1.5 text-xs font-mono dark:border-zinc-700 dark:bg-zinc-900"
                    />
                  </div>
                ))}
              </div>
            </FormField>

            {state.lastPolledAt && Object.keys(state.lastPolledAt).length > 0 && (
              <div className="rounded-md border border-zinc-200 bg-zinc-50 p-2 text-[11px] dark:border-zinc-700 dark:bg-zinc-800">
                <div className="font-semibold text-zinc-700 dark:text-zinc-300">Letzte Polls:</div>
                {Object.entries(state.lastPolledAt).map(([k, v]) => (
                  <div key={k} className="mt-0.5 text-zinc-500">
                    <code>{k}</code>: {v ? new Date(v).toLocaleString('de-DE') : '—'}
                  </div>
                ))}
              </div>
            )}
          </div>
        )}
      </div>

      {error && (
        <div className="flex items-start gap-2 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800 dark:border-red-900/50 dark:bg-red-950/30">
          <AlertTriangle className="h-4 w-4 mt-0.5" />
          <span className="flex-1">{error}</span>
        </div>
      )}

      <div className="flex items-center gap-2">
        <button
          type="button"
          onClick={() => void save()}
          disabled={saving}
          className="inline-flex items-center gap-1.5 rounded-md bg-zinc-900 px-3 py-1.5 text-xs font-medium text-white hover:bg-zinc-800 disabled:opacity-50 dark:bg-zinc-100 dark:text-zinc-900"
        >
          {saving ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Save className="h-3.5 w-3.5" />}
          Speichern
        </button>
        {state.enabled && (
          <button
            type="button"
            onClick={() => void save({ resetLastPolledAt: true })}
            disabled={saving}
            title="Setzt lastPolledAt zurück — der nächste Tick fängt beim aktuellen Zeitpunkt an."
            className="inline-flex items-center gap-1.5 rounded-md border border-zinc-200 bg-white px-3 py-1.5 text-xs text-zinc-700 hover:bg-zinc-50 disabled:opacity-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300"
          >
            <RefreshCw className="h-3.5 w-3.5" />
            Reset lastPolledAt
          </button>
        )}
        {savedAt && (
          <span className="text-[11px] text-emerald-600 dark:text-emerald-400">
            ✓ Gespeichert {new Date(savedAt).toLocaleTimeString('de-DE')}
          </span>
        )}
      </div>
    </div>
  );
}

// ----- Workspaces-Tab ------------------------------------------------------------

function BrandsTab({ workspaces, onSaved }: { workspaces: Workspace[]; onSaved: (slug?: string) => void }) {
  const [editing, setEditing] = useState<Workspace | null>(null);
  const [creating, setCreating] = useState(false);

  if (editing || creating) {
    return (
      <BrandForm
        initial={editing}
        onCancel={() => { setEditing(null); setCreating(false); }}
        onSaved={(slug) => { setEditing(null); setCreating(false); onSaved(slug); }}
      />
    );
  }

  return (
    <div className="space-y-4">
      <div className="flex items-center justify-between">
        <p className="text-sm text-zinc-600 dark:text-zinc-400">{workspaces.length} Workspace{workspaces.length === 1 ? '' : 's'} konfiguriert</p>
        <button
          onClick={() => setCreating(true)}
          className="inline-flex items-center gap-1.5 rounded-md bg-zinc-900 px-3 py-1.5 text-xs font-medium text-white hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900"
        >
          <Plus className="h-3.5 w-3.5" /> Neue Workspace
        </button>
      </div>

      <div className="space-y-2">
        {workspaces.map(b => (
          <button
            key={b.slug}
            onClick={() => setEditing(b)}
            className="flex w-full items-start gap-3 rounded-lg border border-zinc-200 bg-white p-4 text-left transition hover:border-zinc-300 hover:shadow-sm dark:border-zinc-800 dark:bg-zinc-900 dark:hover:border-zinc-700"
          >
            <div className="mt-0.5 h-8 w-8 shrink-0 rounded" style={{ backgroundColor: b.primaryColor }} />
            <div className="min-w-0 flex-1">
              <div className="flex items-center gap-2">
                <span className="font-semibold">{b.name}</span>
                <span className="rounded bg-zinc-100 px-1.5 py-0.5 font-mono text-[10px] text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400">{b.slug}</span>
                {b.companyId != null && <span className="rounded bg-blue-100 px-1.5 py-0.5 text-[10px] font-medium text-blue-700 dark:bg-blue-950/50 dark:text-blue-300">Pool #{b.companyId}</span>}
              </div>
              <div className="mt-1 text-xs text-zinc-500 line-clamp-1">{b.brandVoice}</div>
              <div className="mt-1 text-xs text-zinc-400">{b.senderEmail}</div>
            </div>
          </button>
        ))}
      </div>
    </div>
  );
}

function BrandForm({ initial, onCancel, onSaved }: { initial: Workspace | null; onCancel: () => void; onSaved: (slug?: string) => void }) {
  // brandKit aus DB-Row laden (initial.brandKitJson) oder leeres Skelett für Neu-Anlage
  const initialKit: BrandKit = (initial?.brandKitJson as BrandKit | undefined) ?? { version: 1 };
  const [b, setB] = useState<Partial<Workspace>>(initial ?? {
    slug: '', name: '', primaryColor: '#0066ff', senderDomain: '', senderName: '', senderEmail: '', replyToEmail: '',
    footerText: '', brandVoice: '', imprintUrl: 'https://', privacyUrl: 'https://',
  });
  const [kit, setKit] = useState<BrandKit>(initialKit);
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<{ general: string | null; fields: Record<string, string> }>({ general: null, fields: {} });
  const [suggesting, setSuggesting] = useState(false);
  const [suggestError, setSuggestError] = useState<string | null>(null);
  const [suggestReasoning, setSuggestReasoning] = useState<string | null>(null);

  const clearFieldError = (path: string) => {
    setError(prev => prev.fields[path]
      ? { ...prev, fields: Object.fromEntries(Object.entries(prev.fields).filter(([k]) => k !== path)) }
      : prev);
  };
  const set = <K extends keyof Workspace>(k: K, v: Workspace[K]) => {
    setB(prev => ({ ...prev, [k]: v }));
    clearFieldError(k as string);
  };
  const setHeader = (patch: Partial<NonNullable<BrandKit['header']>>) => {
    setKit(prev => ({ ...prev, header: { ...prev.header, ...patch } }));
    Object.keys(patch).forEach(k => clearFieldError(`brandKit.header.${k}`));
  };
  const setFooter = (patch: Partial<NonNullable<BrandKit['footer']>>) => {
    setKit(prev => ({ ...prev, footer: { ...prev.footer, ...patch } }));
    Object.keys(patch).forEach(k => clearFieldError(`brandKit.footer.${k}`));
  };

  const handleSuggest = async () => {
    if (!b.name || !b.brandVoice) {
      setSuggestError('Bitte erst Workspace-Name und Workspace-Voice ausfüllen — die brauche ich als Kontext.');
      return;
    }
    setSuggesting(true);
    setSuggestError(null);
    setSuggestReasoning(null);
    try {
      const res = await fetch('/api/workspaces/suggest-branding', {
        method: 'POST',
        headers: { 'content-type': 'application/json' },
        body: JSON.stringify({
          brandName: b.name,
          brandVoice: b.brandVoice,
          wordingStyle: b.wordingStyle ?? undefined,
          designStyle: b.designStyle ?? undefined,
          senderDomain: b.senderDomain ?? undefined,
          currentHeader: kit.header,
          currentFooter: kit.footer,
        }),
      });
      const data = await res.json();
      if (!res.ok) {
        setSuggestError(data.error ?? `HTTP ${res.status}`);
        return;
      }
      setKit(prev => ({
        ...prev,
        header: {
          phone: data.header?.phone || prev.header?.phone,
          tagline: data.header?.tagline || prev.header?.tagline,
        },
        footer: {
          companyInfo: data.footer?.companyInfo || prev.footer?.companyInfo,
          legalRegulations: data.footer?.legalRegulations || prev.footer?.legalRegulations,
          complaintBodies: data.footer?.complaintBodies || prev.footer?.complaintBodies,
        },
      }));
      setSuggestReasoning(data.reasoning ?? null);
    } catch (e) {
      setSuggestError(e instanceof Error ? e.message : 'Network error');
    } finally {
      setSuggesting(false);
    }
  };

  const handleSave = async () => {
    setSaving(true);
    setError({ general: null, fields: {} });
    try {
      const res = await fetch('/api/workspaces', {
        method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ ...b, brandKit: kit }),
      });
      const data = await res.json();
      if (!res.ok) {
        const fields: Record<string, string> = data.fieldErrors ?? {};
        const hasFieldErrors = Object.keys(fields).length > 0;
        setError({
          general: hasFieldErrors
            ? 'Bitte markierte Felder prüfen.'
            : (data.error ?? 'Speichern fehlgeschlagen.'),
          fields,
        });
        if (hasFieldErrors) {
          const firstField = Object.keys(fields)[0];
          queueMicrotask(() => {
            document.querySelector<HTMLElement>(`[data-field="${CSS.escape(firstField)}"]`)?.scrollIntoView({
              behavior: 'smooth', block: 'center',
            });
          });
        }
        return;
      }
      onSaved(b.slug);
    } finally { setSaving(false); }
  };

  const handleDelete = async () => {
    if (!initial || !confirm(`Workspace "${initial.name}" wirklich löschen?`)) return;
    setSaving(true);
    await fetch(`/api/workspaces?slug=${initial.slug}`, { method: 'DELETE' });
    onSaved(initial.slug);
  };

  return (
    <div className="space-y-5">
      <header className="flex items-center justify-between">
        <h3 className="text-sm font-semibold">{initial ? `Workspace "${initial.name}" bearbeiten` : 'Neue Workspace anlegen'}</h3>
        <button onClick={onCancel} className="text-xs text-zinc-500 hover:text-zinc-700">← Zurück</button>
      </header>

      {error.general && <div className="rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800 dark:border-red-900/50 dark:bg-red-950/30">{error.general}</div>}

      <FormGroup title="Identität" icon={<Building2 className="h-3.5 w-3.5" />}>
        <FormRow>
          <FormField label="Slug (URL-sicher)" hint="lowercase, Bindestriche" error={error.fields.slug} fieldKey="slug">
            <FormInput value={b.slug ?? ''} onChange={v => set('slug', v)} disabled={!!initial} placeholder="z.B. its" invalid={!!error.fields.slug} />
          </FormField>
          <FormField label="Anzeige-Name" error={error.fields.name} fieldKey="name">
            <FormInput value={b.name ?? ''} onChange={v => set('name', v)} placeholder="ITS" invalid={!!error.fields.name} />
          </FormField>
        </FormRow>
        <FormField
          label="Pool-Zuordnung (optional)"
          hint="Positive Zahl — muss mit „Zuordnung“ eines aktiven M365-Pool-Senders übereinstimmen, wenn beim Versand kein expliziter Absender gewählt wird. Frei wählbar (nicht auf 1–3 begrenzt)."
          error={error.fields.companyId}
          fieldKey="companyId"
        >
          <FormInput
            type="number"
            min={1}
            value={b.companyId?.toString() ?? ''}
            onChange={(v) => {
              const t = v.trim();
              if (!t) {
                set('companyId', null);
                return;
              }
              const n = parseInt(t, 10);
              set('companyId', Number.isFinite(n) && n > 0 ? n : null);
            }}
            placeholder="z. B. 10"
            invalid={!!error.fields.companyId}
          />
        </FormField>
      </FormGroup>

      <FormGroup title="Visuell" icon={<Palette className="h-3.5 w-3.5" />}>
        <FormRow>
          <FormField label="Primary Color" error={error.fields.primaryColor} fieldKey="primaryColor">
            <div className="flex gap-2">
              <input type="color" value={b.primaryColor ?? '#000000'} onChange={e => set('primaryColor', e.target.value)} className="h-9 w-12 cursor-pointer rounded border border-zinc-200 dark:border-zinc-700" />
              <FormInput value={b.primaryColor ?? ''} onChange={v => set('primaryColor', v)} placeholder="#0066ff" invalid={!!error.fields.primaryColor} />
            </div>
          </FormField>
          <FormField label="Secondary Color (optional)" error={error.fields.secondaryColor} fieldKey="secondaryColor">
            <FormInput value={b.secondaryColor ?? ''} onChange={v => set('secondaryColor', v || null)} placeholder="#a0a0a0" invalid={!!error.fields.secondaryColor} />
          </FormField>
        </FormRow>
        <FormField label="Logo-URL (optional)" error={error.fields.logoUrl} fieldKey="logoUrl">
          <FormInput value={b.logoUrl ?? ''} onChange={v => set('logoUrl', v || null)} placeholder="https://example.com/logo.png" invalid={!!error.fields.logoUrl} />
        </FormField>
      </FormGroup>

      <FormGroup title="Tonalität & Wording" icon={<Type className="h-3.5 w-3.5" />}>
        <FormField label="Workspace-Voice (fließt in den AI-Prompt)" hint="Pflichtfeld" error={error.fields.brandVoice} fieldKey="brandVoice">
          <FormTextarea value={b.brandVoice ?? ''} onChange={v => set('brandVoice', v)} rows={3} placeholder="z.B. B2B, sachlich, Sie-Form. Fokus auf Effizienz und Zuverlässigkeit." invalid={!!error.fields.brandVoice} />
        </FormField>
        <FormField label="Wording-Style (optional, präzisere Hinweise)" error={error.fields.wordingStyle} fieldKey="wordingStyle">
          <FormTextarea value={b.wordingStyle ?? ''} onChange={v => set('wordingStyle', v || null)} rows={2} placeholder="z.B. konkrete Zahlen statt Buzzwords, kein Imperativ" invalid={!!error.fields.wordingStyle} />
        </FormField>
        <FormField label="Design-Style (für Hero-Bild-Prompts)" error={error.fields.designStyle} fieldKey="designStyle">
          <FormTextarea value={b.designStyle ?? ''} onChange={v => set('designStyle', v || null)} rows={2} placeholder="z.B. minimalist, viel Whitespace, kalte Farbpalette" invalid={!!error.fields.designStyle} />
        </FormField>
      </FormGroup>

      <FormGroup title="Versand">
        <FormRow>
          <FormField label="Sender-Domain" error={error.fields.senderDomain} fieldKey="senderDomain">
            <FormInput value={b.senderDomain ?? ''} onChange={v => set('senderDomain', v)} placeholder="example.com" invalid={!!error.fields.senderDomain} />
          </FormField>
          <FormField label="Sender-Name" error={error.fields.senderName} fieldKey="senderName">
            <FormInput value={b.senderName ?? ''} onChange={v => set('senderName', v)} placeholder="ITS Team" invalid={!!error.fields.senderName} />
          </FormField>
        </FormRow>
        <FormRow>
          <FormField label="Sender-Email" error={error.fields.senderEmail} fieldKey="senderEmail">
            <FormInput value={b.senderEmail ?? ''} onChange={v => set('senderEmail', v)} placeholder="info@example.com" invalid={!!error.fields.senderEmail} />
          </FormField>
          <FormField label="Reply-To-Email" error={error.fields.replyToEmail} fieldKey="replyToEmail">
            <FormInput value={b.replyToEmail ?? ''} onChange={v => set('replyToEmail', v)} placeholder="reply@example.com" invalid={!!error.fields.replyToEmail} />
          </FormField>
        </FormRow>
        <FormField label="Footer-Text (Impressum-Adresse, einzeilig)" error={error.fields.footerText} fieldKey="footerText">
          <FormTextarea value={b.footerText ?? ''} onChange={v => set('footerText', v)} rows={2} placeholder="ITS GmbH · Musterstraße 1 · 12345 Musterstadt" invalid={!!error.fields.footerText} />
        </FormField>
        <FormField
          label="Shop-Domain (für Login-Direktlinks)"
          hint="optional · wird als {{LOGIN_LINK}} in Mails substituiert"
          error={error.fields.shopDomain}
          fieldKey="shopDomain"
        >
          <FormInput
            value={b.shopDomain ?? ''}
            onChange={v => set('shopDomain', v)}
            placeholder="https://www.versicherungsspartarif.de"
            invalid={!!error.fields.shopDomain}
          />
        </FormField>
      </FormGroup>

      <FormGroup title="Header & Footer (Email-Layout)" icon={<Sparkles className="h-3.5 w-3.5" />}>
        <div className="-mt-1 mb-3 flex items-start justify-between gap-3 rounded-md border border-pink-200 bg-pink-50 p-3 text-xs text-pink-900 dark:border-pink-900/50 dark:bg-pink-950/30 dark:text-pink-200">
          <div className="flex-1">
            <div className="font-medium">KI-gestützte Empfehlung</div>
            <div className="mt-0.5 opacity-80">
              Lass Claude Sonnet 4.6 Vorschläge generieren basierend auf Workspace-Voice + Branche.
              Bei Versicherungsbranche werden Pflichtangaben (§34d GewO, IHK-Reg, §59 VVG, Beschwerdestellen) automatisch eingebaut — mit Platzhaltern für deine konkreten Daten.
            </div>
          </div>
          <button
            type="button"
            onClick={handleSuggest}
            disabled={suggesting}
            className="inline-flex shrink-0 items-center gap-1.5 rounded-md bg-[#ff006a] px-3 py-1.5 text-xs font-semibold text-white transition hover:bg-[#e60060] disabled:opacity-50"
          >
            {suggesting ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Sparkles className="h-3.5 w-3.5" />}
            {suggesting ? 'Generiere …' : 'KI-Vorschlag'}
          </button>
        </div>
        {suggestError && (
          <div className="mb-3 rounded-md border border-red-200 bg-red-50 px-3 py-2 text-xs text-red-800 dark:border-red-900/50 dark:bg-red-950/30">
            {suggestError}
          </div>
        )}
        {suggestReasoning && (
          <div className="mb-3 rounded-md border border-emerald-200 bg-emerald-50 px-3 py-2 text-xs text-emerald-800 dark:border-emerald-900/50 dark:bg-emerald-950/30">
            <strong>KI-Begründung:</strong> {suggestReasoning}
          </div>
        )}

        <h4 className="text-[11px] font-semibold uppercase tracking-wider text-zinc-500">Header (über dem Logo / neben dem Logo)</h4>
        <FormRow>
          <FormField label="Telefon (rechts neben Logo)" hint="optional" error={error.fields['brandKit.header.phone']} fieldKey="brandKit.header.phone">
            <FormInput
              value={kit.header?.phone ?? ''}
              onChange={v => setHeader({ phone: v || undefined })}
              placeholder="+49 89 12345-67"
              invalid={!!error.fields['brandKit.header.phone']}
            />
          </FormField>
          <FormField label="Tagline (unter Logo)" hint="max 60 Zeichen" error={error.fields['brandKit.header.tagline']} fieldKey="brandKit.header.tagline">
            <FormInput
              value={kit.header?.tagline ?? ''}
              onChange={v => setHeader({ tagline: v || undefined })}
              placeholder="Ihr Versicherungsmakler seit 1998"
              invalid={!!error.fields['brandKit.header.tagline']}
            />
          </FormField>
        </FormRow>

        <h4 className="mt-4 text-[11px] font-semibold uppercase tracking-wider text-zinc-500">Footer (unter dem Adress-Block)</h4>

        <FormField
          label="Legal-Pflicht-Block (DE)"
          hint="Anwaltsgeprüfter Block: Firma · Adresse · IHK · §34d · Steuer-Nr · Maklerauftrag-Klausel · Haftungsausschluss. Wird in 9pt gerendert."
          error={error.fields['brandKit.footer.legalFooterText']}
          fieldKey="brandKit.footer.legalFooterText"
        >
          <FormTextarea
            value={kit.footer?.legalFooterText ?? ''}
            onChange={v => setFooter({ legalFooterText: v || undefined })}
            rows={6}
            placeholder={'Firma GmbH, 80339 München, Schwanthalerstr. 124, E-Mail: info@example.de Tel: 089/123456 | IHK München HRB 12345 | §34 Abs.1 GewO Registriernummer D-XXXX-XXXXX-XX | Steuer-Nr.: 123/456/78901 | Datenschutz: privacy@example.de.\nDieses Schreiben erfolgt im Rahmen unseres Maklerauftrags gemäß den gesetzlichen Vorschriften nach §§ 60-62 VVG, sowie §7 VVG, §8 VVG, §10 VVG und §14 VVG.\nHaftungsausschluss: Alle Informationen sind unverbindlich und nicht abschließend.'}
            invalid={!!error.fields['brandKit.footer.legalFooterText']}
          />
        </FormField>

        <FormField
          label="Legal-Pflicht-Block (EN, optional)"
          hint="Englische Reserve. Wird gerendert wenn die Mail-Sprache 'en' ist und dieses Feld gefüllt ist."
          error={error.fields['brandKit.footer.legalFooterTextEn']}
          fieldKey="brandKit.footer.legalFooterTextEn"
        >
          <FormTextarea
            value={kit.footer?.legalFooterTextEn ?? ''}
            onChange={v => setFooter({ legalFooterTextEn: v || undefined })}
            rows={6}
            placeholder={'Company GmbH, 80339 Munich, Schwanthalerstr. 124, E-Mail: info@example.com Tel.: 089/123456 | Section 34(1) GewO registration number: D-XXXX-XXXXX-XX | Tax No.: 123/456/78901.\nThis letter is issued within the scope of our brokerage mandate pursuant to Sections 60-62, 7, 8, 10 and 14 VVG.\nDisclaimer: All information is non-binding and not exhaustive.'}
            invalid={!!error.fields['brandKit.footer.legalFooterTextEn']}
          />
        </FormField>

        <FormField
          label="Standard-Signatur (DE)"
          hint="Wird unter der P.S.-Zeile gerendert. Mehrzeilig erlaubt — z.B. 'Beste Grüße,\\nIhr ITS-Team'. Wenn leer, greift ein generischer Fallback."
          error={error.fields['brandKit.footer.defaultSignature']}
          fieldKey="brandKit.footer.defaultSignature"
        >
          <FormTextarea
            value={kit.footer?.defaultSignature ?? ''}
            onChange={v => setFooter({ defaultSignature: v || undefined })}
            rows={2}
            placeholder={'Beste Grüße,\nIhr Team'}
            invalid={!!error.fields['brandKit.footer.defaultSignature']}
          />
        </FormField>

        <FormField
          label="Standard-Signatur (EN, optional)"
          hint="Englische Reserve. Wird genutzt wenn die Mail-Sprache 'en' ist."
          error={error.fields['brandKit.footer.defaultSignatureEn']}
          fieldKey="brandKit.footer.defaultSignatureEn"
        >
          <FormTextarea
            value={kit.footer?.defaultSignatureEn ?? ''}
            onChange={v => setFooter({ defaultSignatureEn: v || undefined })}
            rows={2}
            placeholder={'Best regards,\nThe team'}
            invalid={!!error.fields['brandKit.footer.defaultSignatureEn']}
          />
        </FormField>

        <FormField
          label="Confidentiality- / Haftungs-Block (DE)"
          hint="Disclaimer-Block: 'Diese E-Mail ist vertraulich…' — wird in 9pt kursiv unter dem Legal-Block gerendert."
          error={error.fields['brandKit.footer.confidentialityNotice']}
          fieldKey="brandKit.footer.confidentialityNotice"
        >
          <FormTextarea
            value={kit.footer?.confidentialityNotice ?? ''}
            onChange={v => setFooter({ confidentialityNotice: v || undefined })}
            rows={5}
            placeholder={'Diese E-Mail und etwaige Anhänge sind vertraulich und nur für den vorgesehenen Empfänger bestimmt. Wenn Sie nicht der Empfänger sind, benachrichtigen Sie bitte den Absender, löschen Sie die Nachricht und verwenden Sie sie nicht. Inhalt und Anhänge dienen ausschließlich der allgemeinen Information.'}
            invalid={!!error.fields['brandKit.footer.confidentialityNotice']}
          />
        </FormField>

        <FormField
          label="Confidentiality- / Haftungs-Block (EN, optional)"
          hint="Englische Reserve."
          error={error.fields['brandKit.footer.confidentialityNoticeEn']}
          fieldKey="brandKit.footer.confidentialityNoticeEn"
        >
          <FormTextarea
            value={kit.footer?.confidentialityNoticeEn ?? ''}
            onChange={v => setFooter({ confidentialityNoticeEn: v || undefined })}
            rows={5}
            placeholder={'This email and any attachments are confidential and intended solely for the addressee. If you are not the intended recipient, please notify the sender, delete this message, and do not use it.'}
            invalid={!!error.fields['brandKit.footer.confidentialityNoticeEn']}
          />
        </FormField>

        <div className="mt-3 flex items-center gap-3 rounded-md border border-zinc-200 bg-zinc-50 px-3 py-2 dark:border-zinc-700 dark:bg-zinc-900/40">
          <input
            id="footer-show-unsubscribe"
            type="checkbox"
            checked={kit.footer?.showUnsubscribe !== false}
            onChange={(e) => setFooter({ showUnsubscribe: e.target.checked })}
            className="h-4 w-4 rounded border-zinc-300 text-zinc-900 focus:ring-zinc-500 dark:border-zinc-600"
          />
          <label htmlFor="footer-show-unsubscribe" className="flex-1 cursor-pointer text-xs text-zinc-700 dark:text-zinc-300">
            <span className="font-medium">Abmelde-Link im Footer anzeigen</span>
            <span className="block text-[11px] text-zinc-500 dark:text-zinc-400">
              Deaktivieren bei Info-/Pflicht-Mails (z.B. Maklervollmacht), wo kein Unsubscribe sinnvoll ist.
            </span>
          </label>
        </div>

        <details className="mt-4 rounded-md border border-zinc-200 bg-white p-3 text-xs dark:border-zinc-700 dark:bg-zinc-900/40">
          <summary className="cursor-pointer text-[11px] font-semibold uppercase tracking-wider text-zinc-500">
            Legacy-Felder (greifen nur wenn Legal-Pflicht-Block oben leer ist)
          </summary>
          <div className="mt-3 space-y-3">
            <FormField
              label="Gesellschaftsdaten (Legacy)"
              hint="Geschäftsführer · HRB · USt-ID · Sitz — mehrzeilig erlaubt"
              error={error.fields['brandKit.footer.companyInfo']}
              fieldKey="brandKit.footer.companyInfo"
            >
              <FormTextarea
                value={kit.footer?.companyInfo ?? ''}
                onChange={v => setFooter({ companyInfo: v || undefined })}
                rows={3}
                placeholder={'Geschäftsführer: [GESCHÄFTSFÜHRER]\nHandelsregister: HRB [HRB-NUMMER], Amtsgericht [GERICHT]\nUSt-IdNr.: [USt-ID]'}
                invalid={!!error.fields['brandKit.footer.companyInfo']}
              />
            </FormField>
            <FormField
              label="Rechtliche Hinweise (Legacy)"
              hint="§34d GewO · IHK-Vermittlerregister · §59 VVG"
              error={error.fields['brandKit.footer.legalRegulations']}
              fieldKey="brandKit.footer.legalRegulations"
            >
              <FormTextarea
                value={kit.footer?.legalRegulations ?? ''}
                onChange={v => setFooter({ legalRegulations: v || undefined })}
                rows={4}
                placeholder={'Versicherungsmakler nach §34d Abs.1 GewO\nIHK-Vermittlerregister-Nr.: D-XXXX-XXXXX-XX'}
                invalid={!!error.fields['brandKit.footer.legalRegulations']}
              />
            </FormField>
            <FormField
              label="Beschwerdestellen (Legacy)"
              hint="Pflicht nach §15 VersVermV bei Versicherungsbrands"
              error={error.fields['brandKit.footer.complaintBodies']}
              fieldKey="brandKit.footer.complaintBodies"
            >
              <FormTextarea
                value={kit.footer?.complaintBodies ?? ''}
                onChange={v => setFooter({ complaintBodies: v || undefined })}
                rows={3}
                placeholder={'Versicherungsombudsmann e.V., Postfach 080632, 10006 Berlin\nBaFin, Graurheindorfer Str. 108, 53117 Bonn'}
                invalid={!!error.fields['brandKit.footer.complaintBodies']}
              />
            </FormField>
          </div>
        </details>

        <h4 className="mt-5 text-[11px] font-semibold uppercase tracking-wider text-zinc-500">Footer-Modus</h4>
        <div className="mt-2 flex gap-2">
          <button
            type="button"
            onClick={() => setFooter({ mode: 'structured' })}
            className={cn(
              'flex-1 rounded-md border px-3 py-2 text-xs font-medium transition',
              (kit.footer?.mode ?? 'structured') === 'structured'
                ? 'border-zinc-900 bg-zinc-900 text-white dark:border-zinc-100 dark:bg-zinc-100 dark:text-zinc-900'
                : 'border-zinc-200 bg-white text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800',
            )}
          >
            Standard (aus Feldern oben)
          </button>
          <button
            type="button"
            onClick={() => setFooter({ mode: 'mjml' })}
            className={cn(
              'flex-1 rounded-md border px-3 py-2 text-xs font-medium transition',
              kit.footer?.mode === 'mjml'
                ? 'border-zinc-900 bg-zinc-900 text-white dark:border-zinc-100 dark:bg-zinc-100 dark:text-zinc-900'
                : 'border-zinc-200 bg-white text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-300 dark:hover:bg-zinc-800',
            )}
          >
            Eigenes MJML
          </button>
        </div>

        {kit.footer?.mode === 'mjml' && (
          <FormField
            label="Custom Footer (MJML)"
            hint="Ersetzt den kompletten Footer-Bereich. Platzhalter erlaubt: {{BROWSER_URL}}, {{IMPRINT_URL}}, {{PRIVACY_URL}}, {{UNSUBSCRIBE_URL}} — werden zur Send-Zeit ersetzt."
            error={error.fields['brandKit.footer.customMjml']}
            fieldKey="brandKit.footer.customMjml"
          >
            <FormTextarea
              value={kit.footer?.customMjml ?? ''}
              onChange={v => setFooter({ customMjml: v || undefined })}
              rows={12}
              placeholder={'<mj-section background-color="#f4f4f5" padding="16px 24px">\n  <mj-column>\n    <mj-text font-size="11px" color="#a1a1aa" align="center" line-height="1.6">\n      Deine Firma GmbH · Adresse · 12345 Stadt<br/>\n      <a href="{{BROWSER_URL}}" style="color:#a1a1aa">Im Browser ansehen</a> ·\n      <a href="{{IMPRINT_URL}}" style="color:#a1a1aa">Impressum</a> ·\n      <a href="{{PRIVACY_URL}}" style="color:#a1a1aa">Datenschutz</a> ·\n      <a href="{{UNSUBSCRIBE_URL}}" style="color:#a1a1aa">Abmelden</a>\n    </mj-text>\n  </mj-column>\n</mj-section>'}
              invalid={!!error.fields['brandKit.footer.customMjml']}
            />
          </FormField>
        )}
      </FormGroup>

      <FormGroup title="Rechtliches">
        <FormRow>
          <FormField label="Impressum-URL" error={error.fields.imprintUrl} fieldKey="imprintUrl">
            <FormInput value={b.imprintUrl ?? ''} onChange={v => set('imprintUrl', v)} placeholder="https://example.com/impressum" invalid={!!error.fields.imprintUrl} />
          </FormField>
          <FormField label="Datenschutz-URL" error={error.fields.privacyUrl} fieldKey="privacyUrl">
            <FormInput value={b.privacyUrl ?? ''} onChange={v => set('privacyUrl', v)} placeholder="https://example.com/datenschutz" invalid={!!error.fields.privacyUrl} />
          </FormField>
        </FormRow>
      </FormGroup>

      <EmailAttributionFormGroup b={b} set={set} error={error} />

      <div className="flex items-center justify-between border-t border-zinc-200 pt-4 dark:border-zinc-800">
        {initial ? (
          <button onClick={handleDelete} className="inline-flex items-center gap-1.5 rounded-md border border-red-200 px-3 py-1.5 text-xs font-medium text-red-700 hover:bg-red-50 dark:border-red-900/50 dark:text-red-300 dark:hover:bg-red-950/30">
            <Trash2 className="h-3.5 w-3.5" /> Löschen
          </button>
        ) : <span />}
        <div className="flex gap-2">
          <button onClick={onCancel} className="rounded-md border border-zinc-200 px-3 py-1.5 text-xs font-medium text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-300">Abbrechen</button>
          <button onClick={handleSave} disabled={saving} className="inline-flex items-center gap-1.5 rounded-md bg-zinc-900 px-3 py-1.5 text-xs font-medium text-white hover:bg-zinc-800 disabled:opacity-50 dark:bg-zinc-100 dark:text-zinc-900">
            {saving ? <Loader2 className="h-3.5 w-3.5 animate-spin" /> : <Save className="h-3.5 w-3.5" />}
            {saving ? 'Speichere …' : 'Speichern'}
          </button>
        </div>
      </div>
    </div>
  );
}

// ----- Prompts-Tab -----------------------------------------------------------

function PromptsTab({ settings, onSave }: { settings: SettingsBundle; onSave: (patch: Partial<SettingsBundle>) => Promise<void> }) {
  const [genPrompt, setGenPrompt] = useState(settings.systemPromptGenerate);
  const [sugPrompt, setSugPrompt] = useState(settings.systemPromptSuggest);
  const [imgPrompt, setImgPrompt] = useState(settings.systemPromptImage);
  const [saving, setSaving] = useState<'gen' | 'sug' | 'img' | null>(null);

  const dirtyGen = genPrompt !== settings.systemPromptGenerate;
  const dirtySug = sugPrompt !== settings.systemPromptSuggest;
  const dirtyImg = imgPrompt !== settings.systemPromptImage;

  const resetDefault = async (which: 'gen' | 'sug' | 'img') => {
    if (!confirm('Prompt auf System-Default zurücksetzen?')) return;
    const res = await fetch('/api/settings/defaults');
    if (res.ok) {
      const defaults = await res.json();
      if (which === 'gen') setGenPrompt(defaults.systemPromptGenerate);
      else if (which === 'sug') setSugPrompt(defaults.systemPromptSuggest);
      else setImgPrompt(defaults.systemPromptImage);
    }
  };

  return (
    <div className="space-y-6">
      <div>
        <h3 className="text-sm font-semibold">KI-System-Prompts</h3>
        <p className="mt-1 text-xs text-zinc-500">Diese Prompts steuern das LLM-Verhalten. Vorsicht bei Änderungen — Anti-Spam-Direktiven nicht entfernen.</p>
      </div>

      <PromptEditor
        title="Generate-Prompt"
        hint="Master-Prompt für die Email-Generierung (Sonnet → Strategy + MJML)"
        value={genPrompt}
        dirty={dirtyGen}
        onChange={setGenPrompt}
        onReset={() => resetDefault('gen')}
        onSave={async () => { setSaving('gen'); await onSave({ systemPromptGenerate: genPrompt }); setSaving(null); }}
        saving={saving === 'gen'}
      />

      <PromptEditor
        title="Suggest-Prompt"
        hint="Master-Prompt für die KI-Briefing-Vorschläge"
        value={sugPrompt}
        dirty={dirtySug}
        onChange={setSugPrompt}
        onReset={() => resetDefault('sug')}
        onSave={async () => { setSaving('sug'); await onSave({ systemPromptSuggest: sugPrompt }); setSaving(null); }}
        saving={saving === 'sug'}
      />

      <PromptEditor
        title="Image-Prompt"
        hint="Stil-Direktiven für die Hero-Bild-Generierung (fal.ai). Werden an den Image-Brief angehängt. Platzhalter: {BRAND_PRIMARY_COLOR}, {BRAND_NAME}. Tipp: 'no text or logos…' entfernen wenn das Modell Text ins Bild schreiben soll."
        value={imgPrompt}
        dirty={dirtyImg}
        onChange={setImgPrompt}
        onReset={() => resetDefault('img')}
        onSave={async () => { setSaving('img'); await onSave({ systemPromptImage: imgPrompt }); setSaving(null); }}
        saving={saving === 'img'}
      />
    </div>
  );
}

function PromptEditor({ title, hint, value, dirty, onChange, onReset, onSave, saving }: {
  title: string; hint: string; value: string; dirty: boolean;
  onChange: (v: string) => void; onReset: () => void; onSave: () => void; saving: boolean;
}) {
  return (
    <div className="space-y-2">
      <div className="flex items-baseline justify-between">
        <div>
          <h4 className="text-sm font-medium">{title}</h4>
          <p className="text-[11px] text-zinc-500">{hint} · {value.length} Zeichen</p>
        </div>
        <div className="flex gap-2">
          <button onClick={onReset} className="inline-flex items-center gap-1 rounded-md border border-zinc-200 px-2 py-1 text-[11px] text-zinc-600 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-400">
            <RotateCcw className="h-3 w-3" /> Default
          </button>
          <button
            onClick={onSave}
            disabled={!dirty || saving}
            className="inline-flex items-center gap-1 rounded-md bg-zinc-900 px-2 py-1 text-[11px] font-medium text-white disabled:opacity-40 hover:bg-zinc-800 dark:bg-zinc-100 dark:text-zinc-900"
          >
            {saving ? <Loader2 className="h-3 w-3 animate-spin" /> : <Save className="h-3 w-3" />}
            Speichern
          </button>
        </div>
      </div>
      <textarea
        value={value}
        onChange={e => onChange(e.target.value)}
        rows={14}
        className="w-full resize-y rounded-md border border-zinc-200 bg-white px-3 py-2 font-mono text-[11px] leading-relaxed dark:border-zinc-700 dark:bg-zinc-900"
      />
    </div>
  );
}

// ----- Form Helpers ----------------------------------------------------------

/**
 * Section "Email-Attribution" pro Workspace (Phase 3).
 * Editiert: attributionModel, attributionLookbackDays, webhookSecret,
 * ga4PropertyId, cumasRecipientField, activeConversionKinds.
 */
const ALL_KINDS = ['order', 'lead', 'magic_login', 'form_submit'] as const;
const KIND_LABELS: Record<typeof ALL_KINDS[number], string> = {
  order: 'Order',
  lead: 'Lead',
  magic_login: 'Magic-Login',
  form_submit: 'Form-Submit',
};

function EmailAttributionFormGroup({
  b,
  set,
  error,
}: {
  b: Partial<Workspace>;
  set: <K extends keyof Workspace>(k: K, v: Workspace[K]) => void;
  error: { general: string | null; fields: Record<string, string> };
}) {
  const [showSecret, setShowSecret] = useState(false);
  const model = b.attributionModel ?? 'last-click';
  const lookback = b.attributionLookbackDays ?? 30;
  const kinds = b.activeConversionKinds ?? [...ALL_KINDS];

  const generateSecret = () => {
    // 32 Bytes als URL-safe Base64-Replacement → ASCII, ohne +/=
    const bytes = new Uint8Array(32);
    crypto.getRandomValues(bytes);
    const secret = Array.from(bytes, (b) => b.toString(16).padStart(2, '0')).join('');
    set('webhookSecret', secret);
    setShowSecret(true);
  };

  const toggleKind = (kind: typeof ALL_KINDS[number]) => {
    const next = kinds.includes(kind) ? kinds.filter((k) => k !== kind) : [...kinds, kind];
    // Mindestens einen aktiv lassen — UI-Hint statt Throw
    if (next.length === 0) return;
    set('activeConversionKinds', next.sort((a, b) => ALL_KINDS.indexOf(a) - ALL_KINDS.indexOf(b)));
  };

  return (
    <FormGroup title="Email-Attribution" icon={<BarChart3 className="h-3.5 w-3.5" />}>
      <FormRow>
        <FormField
          label="Attribution-Modell"
          hint="Wie Conversions auf Email-Touches verteilt werden"
          fieldKey="attributionModel"
        >
          <select
            value={model}
            onChange={(e) => set('attributionModel', e.target.value as Workspace['attributionModel'])}
            className="w-full rounded-md border border-zinc-200 bg-white px-2.5 py-1.5 text-sm dark:border-zinc-700 dark:bg-zinc-900"
          >
            <option value="last-click">Last-Click (B2C-Default)</option>
            <option value="first-click">First-Click (B2B-Funnel)</option>
            <option value="linear">Linear (gleichmäßig auf alle Touches)</option>
            <option value="time-decay">Time-Decay (näher = mehr Credit)</option>
          </select>
        </FormField>
        <FormField
          label="Lookback-Tage"
          hint="Touches älter werden ignoriert"
          error={error.fields.attributionLookbackDays}
          fieldKey="attributionLookbackDays"
        >
          <FormInput
            type="number"
            value={String(lookback)}
            onChange={(v) => set('attributionLookbackDays', Math.max(1, Math.min(365, parseInt(v, 10) || 30)))}
            invalid={!!error.fields.attributionLookbackDays}
          />
        </FormField>
      </FormRow>

      <FormField
        label="Webhook-Secret (HMAC)"
        hint="Pro Workspace individuell. Generieren bei Erstkonfiguration; ggf. mit Shop koordinieren."
        error={error.fields.webhookSecret}
        fieldKey="webhookSecret"
      >
        <div className="flex items-center gap-2">
          <div className="relative flex-1">
            <FormInput
              type={showSecret ? 'text' : 'password'}
              value={b.webhookSecret ?? ''}
              onChange={(v) => set('webhookSecret', v)}
              placeholder="Leer = globales MAILFORGE_WEBHOOK_SECRET wird genutzt"
              invalid={!!error.fields.webhookSecret}
            />
          </div>
          <button
            type="button"
            onClick={() => setShowSecret((s) => !s)}
            title={showSecret ? 'Verbergen' : 'Anzeigen'}
            className="inline-flex h-8 w-8 items-center justify-center rounded-md border border-zinc-200 text-zinc-600 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800"
          >
            {showSecret ? <EyeOff className="h-3.5 w-3.5" /> : <Eye className="h-3.5 w-3.5" />}
          </button>
          <button
            type="button"
            onClick={generateSecret}
            title="Neues Secret generieren (64 Hex-Zeichen)"
            className="inline-flex items-center gap-1 rounded-md border border-zinc-200 px-2 py-1.5 text-[11px] font-medium text-zinc-700 hover:bg-zinc-50 dark:border-zinc-700 dark:text-zinc-300 dark:hover:bg-zinc-800"
          >
            <Key className="h-3.5 w-3.5" /> Generieren
          </button>
        </div>
      </FormField>

      <FormRow>
        <FormField
          label="GA4-Property-ID"
          hint="z.B. properties/123456789 oder nackte ID"
          error={error.fields.ga4PropertyId}
          fieldKey="ga4PropertyId"
        >
          <FormInput
            value={b.ga4PropertyId ?? ''}
            onChange={(v) => set('ga4PropertyId', v)}
            placeholder="properties/123456789"
            invalid={!!error.fields.ga4PropertyId}
          />
        </FormField>
        <FormField
          label="Cumas-Recipient-Feld"
          hint="Dot-Path; leer = globales Setting"
          error={error.fields.cumasRecipientField}
          fieldKey="cumasRecipientField"
        >
          <FormInput
            value={b.cumasRecipientField ?? ''}
            onChange={(v) => set('cumasRecipientField', v)}
            placeholder="extra_data.mf_rcp"
            invalid={!!error.fields.cumasRecipientField}
          />
        </FormField>
      </FormRow>

      <FormField
        label="Aktive Conversion-Kinds"
        hint="Nur diese Kinds zählen in Stats für diese Workspace"
        fieldKey="activeConversionKinds"
      >
        <div className="flex flex-wrap gap-1.5">
          {ALL_KINDS.map((k) => {
            const on = kinds.includes(k);
            return (
              <button
                key={k}
                type="button"
                onClick={() => toggleKind(k)}
                className={cn(
                  'rounded-md border-2 px-2.5 py-1 text-xs font-semibold transition',
                  on
                    ? 'border-[#ff006a] bg-[#ff006a] text-white shadow-sm'
                    : 'border-zinc-200 bg-white text-zinc-600 hover:border-zinc-300 dark:border-zinc-700 dark:bg-zinc-900 dark:text-zinc-400',
                )}
              >
                {KIND_LABELS[k]}
              </button>
            );
          })}
        </div>
      </FormField>
    </FormGroup>
  );
}

function FormGroup({ title, icon, children }: { title: string; icon?: React.ReactNode; children: React.ReactNode }) {
  return (
    <fieldset className="space-y-3 rounded-lg border border-zinc-200 p-4 dark:border-zinc-800">
      <legend className="inline-flex items-center gap-1.5 px-1 text-[11px] font-semibold uppercase tracking-wider text-zinc-500">
        {icon} {title}
      </legend>
      {children}
    </fieldset>
  );
}

function FormRow({ children }: { children: React.ReactNode }) {
  return <div className="grid grid-cols-2 gap-3">{children}</div>;
}

function FormField({ label, hint, error, fieldKey, children }: {
  label: string; hint?: string; error?: string; fieldKey?: string; children: React.ReactNode;
}) {
  return (
    <div className="flex flex-col gap-1" data-field={fieldKey}>
      <label className={cn(
        'text-[11px] font-medium',
        error ? 'text-red-700 dark:text-red-400' : 'text-zinc-700 dark:text-zinc-300',
      )}>
        {label} {hint && <span className="text-[10px] font-normal text-zinc-400">· {hint}</span>}
      </label>
      {children}
      {error && <span className="text-[11px] text-red-600 dark:text-red-400">{error}</span>}
    </div>
  );
}

function FormInput({ value, onChange, placeholder, type = 'text', disabled, invalid, min }: {
  value: string; onChange: (v: string) => void; placeholder?: string; type?: string; disabled?: boolean; invalid?: boolean; min?: number;
}) {
  return (
    <input
      type={type}
      value={value}
      min={min}
      onChange={e => onChange(e.target.value)}
      placeholder={placeholder}
      disabled={disabled}
      aria-invalid={invalid || undefined}
      className={cn(
        'w-full rounded-md border bg-white px-2.5 py-1.5 text-sm transition focus:outline-none focus:ring-2 disabled:bg-zinc-50 disabled:text-zinc-500 dark:bg-zinc-900 dark:disabled:bg-zinc-800',
        invalid
          ? 'border-red-400 focus:border-red-500 focus:ring-red-500/20 dark:border-red-700'
          : 'border-zinc-200 focus:border-zinc-900 focus:ring-zinc-900/10 dark:border-zinc-700',
      )}
    />
  );
}

function FormTextarea({ value, onChange, placeholder, rows = 3, invalid }: {
  value: string; onChange: (v: string) => void; placeholder?: string; rows?: number; invalid?: boolean;
}) {
  return (
    <textarea
      value={value}
      onChange={e => onChange(e.target.value)}
      placeholder={placeholder}
      rows={rows}
      aria-invalid={invalid || undefined}
      className={cn(
        'w-full resize-y rounded-md border bg-white px-2.5 py-1.5 text-sm focus:outline-none focus:ring-2 dark:bg-zinc-900',
        invalid
          ? 'border-red-400 focus:border-red-500 focus:ring-red-500/20 dark:border-red-700'
          : 'border-zinc-200 focus:border-zinc-900 focus:ring-zinc-900/10 dark:border-zinc-700',
      )}
    />
  );
}
