const OUTREACH_STAGE_LABELS = {
  review: { de: "Zu prüfen", en: "Review" },
  ready: { de: "Bereit", en: "Ready" },
  connecting: { de: "Kontaktaufnahme", en: "Connecting" },
  contacted: { de: "Erstkontakt gesendet", en: "Contacted" },
  followed_up: { de: "Follow-up gesendet", en: "Follow-up sent" },
  conversation: { de: "Im Gespräch", en: "In conversation" },
  paused: { de: "Pausiert", en: "Paused" },
  closed: { de: "Beendet", en: "Closed" },
};

const OUTREACH_CONNECTION_STATES = ["unknown", "not_requested", "pending", "connected"];
const OUTREACH_DETAIL_FIELDS = {
  contact: ["first", "last", "title", "email", "phone", "linkedinUrl"],
  company: ["name", "domain", "website", "industry", "size", "linkedinUrl"],
  research: ["position", "employeeEstimate", "estimatedRevenue", "industry", "website", "linkedinUrl", "domain", "research"],
};

function outreachStageLabel(stage, lang) {
  return OUTREACH_STAGE_LABELS[stage] ? OUTREACH_STAGE_LABELS[stage][lang === "en" ? "en" : "de"] : String(stage || "Unbekannt");
}

function outreachConnectionLabel(state, lang) {
  const labels = {
    unknown: { de: "Vernetzung unbekannt", en: "Connection unknown" },
    not_requested: { de: "Nicht angefragt", en: "Not requested" },
    pending: { de: "Anfrage offen", en: "Request pending" },
    connected: { de: "Vernetzt", en: "Connected" },
  };
  return labels[state] ? labels[state][lang === "en" ? "en" : "de"] : String(state || "Unbekannt");
}

const OUTREACH_DETAIL_TEXT = {
  back: { de: "Outreach", en: "Outreach" }, openCompany: { de: "Firma öffnen", en: "Open company" }, unknownBrand: { de: "Unbekannte Brand", en: "Unknown brand" },
  drafts: { de: "Entwürfe", en: "Drafts" }, saved: { de: "Gespeichert", en: "Saved" }, unsaved: { de: "Ungespeichert", en: "Unsaved" }, pitch: { de: "Pitch", en: "Pitch" }, copy: { de: "Kopieren", en: "Copy" }, linkedin: { de: "LinkedIn öffnen", en: "Open LinkedIn" }, followup: { de: "Follow-up", en: "Follow-up" }, reply: { de: "Reply", en: "Reply" }, saving: { de: "Speichert…", en: "Saving…" }, save: { de: "Speichern", en: "Save" },
  actions: { de: "Aktionen", en: "Actions" }, active: { de: "Aktiv", en: "Active" }, notActive: { de: "Noch nicht aktiv", en: "Not active yet" }, markSent: { de: "Als gesendet markieren", en: "Mark as sent" }, logReply: { de: "Antwort loggen", en: "Log reply" }, noNeed: { de: "Kein Bedarf", en: "No need" }, stopContact: { de: "Kontakt stoppen", en: "Stop contact" }, research: { de: "Research", en: "Research" }, unknownEmail: { de: "E-Mail unbekannt", en: "Email unknown" }, unknownDomain: { de: "Domain unbekannt", en: "Domain unknown" },
  activation: { de: "Aktivierung", en: "Activation" }, owner: { de: "Owner", en: "Owner" }, chooseOwner: { de: "Owner auswählen", en: "Choose owner" }, firstTask: { de: "Erste Aufgabe", en: "First task" }, nextStep: { de: "Nächster Schritt", en: "Next step" }, due: { de: "Fälligkeit", en: "Due date" }, activate: { de: "Aktivieren", en: "Activate" }, tasks: { de: "Aufgaben", en: "Tasks" }, unknownDue: { de: "Fälligkeit unbekannt", en: "Due date unknown" }, timeline: { de: "Verlauf", en: "Timeline" }, import: { de: "Import", en: "Import" },
  sendDialog: { de: "Als gesendet markieren", en: "Mark as sent" }, sendType: { de: "Versandart", en: "Send type" }, requestSent: { de: "Anfrage gesendet", en: "Connection request sent" }, pitchSent: { de: "Pitch gesendet", en: "Pitch sent" }, followupSent: { de: "Follow-up gesendet", en: "Follow-up sent" }, actualTime: { de: "Tatsächlicher Zeitpunkt", en: "Actual time" }, cancel: { de: "Abbrechen", en: "Cancel" }, confirmSend: { de: "Versand bestätigen", en: "Confirm send" }, replyDialog: { de: "Antwort loggen", en: "Log reply" }, sentiment: { de: "Sentiment", en: "Sentiment" }, unknown: { de: "Unbekannt", en: "Unknown" }, positive: { de: "Positiv", en: "Positive" }, neutral: { de: "Neutral", en: "Neutral" }, negative: { de: "Negativ", en: "Negative" }, saveReply: { de: "Antwort speichern", en: "Save reply" },
  agentDevices: { de: "Lokale Agent-Geräte", en: "Local agent devices" }, agentPairHint: { de: "Pairing erzeugt ein einmal sichtbares Geräte-Credential. Keine Modell-API-Tokens.", en: "Pairing creates a device credential shown once. No model API tokens." }, agentName: { de: "Gerätename", en: "Device name" }, agentProvider: { de: "Lokaler Provider", en: "Local provider" }, agentCodex: { de: "Codex Subscription", en: "Codex subscription" }, agentClaude: { de: "Claude Subscription", en: "Claude subscription" }, agentPair: { de: "Gerät pairen", en: "Pair device" }, agentCredential: { de: "Credential kopieren", en: "Copy credential" }, agentCredentialCopied: { de: "Credential kopiert", en: "Credential copied" }, agentRevoke: { de: "Widerrufen", en: "Revoke" }, agentRevoked: { de: "Widerrufen", en: "Revoked" }, agentExpires: { de: "Läuft ab", en: "Expires" }, agentLastSeen: { de: "Zuletzt gesehen", en: "Last seen" }, agentNeverSeen: { de: "Noch nicht gesehen", en: "Never seen" }, agentPairSuccess: { de: "Gerät gepairt. Credential jetzt kopieren.", en: "Device paired. Copy the credential now." }, agentRevokeSuccess: { de: "Gerät widerrufen.", en: "Device revoked." }, runnerCommand: { de: "Runner-Befehl kopieren", en: "Copy runner command" }, runnerCommandCopied: { de: "Runner-Befehl kopiert", en: "Runner command copied" }, runnerCommandHint: { de: "Startet genau einen lokalen Job. Keine API-Tokens.", en: "Starts exactly one local job. No API tokens." },
  aiAssistant: { de: "KI-Assistent", en: "AI assistant" }, aiLocalHint: { de: "Lokaler Codex-/Claude-Runner erstellt nur Drafts und Reviews. Freigabe und LinkedIn-Versand bleiben menschlich.", en: "The local Codex/Claude runner creates drafts and reviews only. Approval and LinkedIn sending stay human." }, aiKind: { de: "Nachrichtentyp", en: "Message type" }, aiDraft: { de: "KI-Draft anfordern", en: "Request AI draft" }, aiReview: { de: "KI-Review anfordern", en: "Request AI review" }, agentJobRequested: { de: "Agent-Job angefordert", en: "Agent job requested" }, noRevision: { de: "Noch keine Revision vorhanden", en: "No revision yet" }, revision: { de: "Revision", en: "Revision" }, sourceAgent: { de: "Agent", en: "Agent" }, sourceHuman: { de: "Mensch", en: "Human" }, reviewSummary: { de: "Review-Zusammenfassung", en: "Review summary" }, noReview: { de: "Noch kein Review vorhanden", en: "No review yet" }, approve: { de: "Freigeben", en: "Approve" }, approved: { de: "Menschlich freigegeben", en: "Human-approved" }, approvalSaved: { de: "Freigabe gespeichert", en: "Approval saved" }, revokeReason: { de: "Grund für Widerruf", en: "Revocation reason" }, revokeApproval: { de: "Freigabe widerrufen", en: "Revoke approval" }, prepareSend: { de: "Versand vorbereiten", en: "Prepare send" }, sendPrepared: { de: "Versand vorbereitet", en: "Send prepared" }, expires: { de: "Gültig bis", en: "Expires" },
  status: { de: "Status", en: "Stage" }, connection: { de: "Vernetzung", en: "Connection" }, statusReason: { de: "Begründung", en: "Reason" }, statusReasonHint: { de: "Nur bei Pause, Beendigung oder Korrektur", en: "Required for pause, close or correction" }, saveStatus: { de: "Status speichern", en: "Save stage" }, details: { de: "Details", en: "Details" }, saveDetails: { de: "Daten speichern", en: "Save details" }, totalOf: { de: "von", en: "of" }, exportLoaded: { de: "Geladene exportieren", en: "Export loaded" }, resetFilters: { de: "Filter zurücksetzen", en: "Reset filters" }, nativeCreate: { de: "Neuen Kontakt anlegen", en: "Create contact" }, pushEnable: { de: "Browser-Push aktivieren", en: "Enable browser push" }, pushEnabled: { de: "Browser-Push aktiviert", en: "Browser push enabled" }, pushNotConfigured: { de: "Browser-Push ist in Staging noch nicht konfiguriert.", en: "Browser push is not configured in Staging yet." },
  first: { de: "Vorname", en: "First name" }, last: { de: "Nachname", en: "Last name" }, title: { de: "Position", en: "Title" }, email: { de: "E-Mail", en: "Email" }, phone: { de: "Telefon", en: "Phone" }, linkedinUrl: { de: "LinkedIn-URL", en: "LinkedIn URL" }, companyName: { de: "Firmenname", en: "Company name" }, domain: { de: "Domain", en: "Domain" }, website: { de: "Website", en: "Website" }, industry: { de: "Branche", en: "Industry" }, size: { de: "Größe", en: "Size" }, position: { de: "Position", en: "Position" }, employeeEstimate: { de: "Mitarbeitende (Schätzung)", en: "Estimated employees" }, estimatedRevenue: { de: "Jahresumsatz (Schätzung)", en: "Estimated annual revenue" },
  createTitle: { de: "Neuer Outreach-Kontakt", en: "New outreach contact" }, nativeDraftHint: { de: "Neue Kontakte bleiben Entwurf, bis Owner und erste Aufgabe gesetzt sind.", en: "New contacts stay draft until an owner and first task are set." }, campaign: { de: "Kampagne", en: "Campaign" }, noCampaign: { de: "Kampagne auswählen", en: "Choose campaign" }, fullName: { de: "Voller Name", en: "Full name" }, create: { de: "Anlegen", en: "Create" }, created: { de: "Kontakt angelegt", en: "Contact created" },
  };

function outreachDetailText(lang, key) {
  const value = OUTREACH_DETAIL_TEXT[key];
  return value ? value[lang === "en" ? "en" : "de"] : key;
}

function outreachContactLabel(item) {
  return item.contactName || item.personName || item.fullName || "Unbekannt";
}

function outreachFilterStorageKey() { return "mesper.crm.outreach.filters"; }

function createOutreachAgentCredential() {
  const bytes = new Uint8Array(36);
  if (typeof crypto !== "undefined" && typeof crypto.getRandomValues === "function") crypto.getRandomValues(bytes);
  else for (let index = 0; index < bytes.length; index += 1) bytes[index] = Math.floor(Math.random() * 256);
  return btoa(String.fromCharCode(...bytes)).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/g, "");
}

function withOutreachTimeout(promise, milliseconds, message) {
  let timeoutId;
  const timeout = new Promise((_, reject) => {
    timeoutId = setTimeout(() => reject(Object.assign(new Error(message), { code: "OUTREACH_TIMEOUT" })), milliseconds);
  });
  return Promise.race([promise, timeout]).finally(() => clearTimeout(timeoutId));
}

function outreachAgentGatewayUrl() {
  const root = typeof window !== "undefined" ? window : {};
  const runtime = root.__MESPER_RUNTIME_CONFIG__;
  const supabaseUrl = runtime?.supabaseUrl || root.MesperDB?.sb?.supabaseUrl || "";
  return supabaseUrl ? `${String(supabaseUrl).replace(/\/$/, "")}/functions/v1/crm-outreach-agent` : "";
}

function outreachAgentRunnerCommand(provider, deviceId, credential) {
  const gateway = outreachAgentGatewayUrl();
  if (!gateway || !deviceId || !credential) return "";
  return [
    `OUTREACH_AGENT_PROVIDER=${provider}`,
    `OUTREACH_AGENT_GATEWAY_URL=${gateway}`,
    `OUTREACH_AGENT_DEVICE_ID=${deviceId}`,
    `OUTREACH_AGENT_CREDENTIAL=${credential}`,
    "OUTREACH_AGENT_BRAIN_ROOT=/Users/renedallmann/brain",
    "OUTREACH_AGENT_BRAIN_FILES=01-Identity/voice-outreach.md",
    "OUTREACH_AGENT_ONCE=true",
    "node tools/outreach-agent-runner.mjs",
  ].join(" ");
}

function readOutreachFilters() {
  try {
    const stored = JSON.parse(sessionStorage.getItem(outreachFilterStorageKey()) || "null");
    if (stored && typeof stored === "object") return { search: "", ownerId: "", stage: "", connectionState: "", executionState: "", campaignId: "", dueOnly: false, ...stored };
  } catch (_) {}
  return { search: "", ownerId: "", stage: "", connectionState: "", executionState: "", campaignId: "", dueOnly: false };
}

function saveOutreachFilters(filters) {
  try { sessionStorage.setItem(outreachFilterStorageKey(), JSON.stringify(filters)); } catch (_) {}
}

function emptyOutreachWorkflow() {
  return { messages: [], revisions: [], reviews: [], approvals: [], preparations: [] };
}

function workflowRevision(workflow, kind) {
  const message = (workflow?.messages || []).find((item) => item.kind === kind);
  if (!message) return null;
  return (workflow?.revisions || []).find((revision) => revision.id === message.currentRevisionId) || null;
}

function workflowReview(workflow, revisionId) {
  return (workflow?.reviews || []).filter((review) => review.revisionId === revisionId).sort((a, b) => String(b.createdAt || "").localeCompare(String(a.createdAt || "")))[0] || null;
}

function workflowApproval(workflow, revisionId) {
  return (workflow?.approvals || []).find((approval) => approval.revisionId === revisionId && !approval.revokedAt) || null;
}

function workflowPreparation(workflow, revisionId) {
  return (workflow?.preparations || []).find((preparation) => preparation.revisionId === revisionId && !preparation.usedAt && new Date(preparation.expiresAt || 0).getTime() > Date.now()) || null;
}

function downloadOutreachCsv(items, lang) {
  const columns = lang === "de" ? ["Brand", "Kontakt", "Status", "Vernetzung", "Ausführung", "Owner", "Kampagne"] : ["Brand", "Contact", "Stage", "Connection", "Execution", "Owner", "Campaign"];
  const rows = (items || []).map((item) => [item.brandName || item.brand || "", outreachContactLabel(item), item.stage || "", item.connectionState || "", item.executionState || "", item.ownerName || "", item.campaignName || ""]);
  const csv = [columns, ...rows].map((row) => row.map((value) => "\"" + String(value ?? "").replace(/"/g, "\"\"") + "\"").join(",")).join("\r\n");
  const blob = new Blob(["\ufeff" + csv], { type: "text/csv;charset=utf-8" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = "outreach-" + new Date().toISOString().slice(0, 10) + ".csv";
  document.body.appendChild(link); link.click(); link.remove();
  setTimeout(() => URL.revokeObjectURL(url), 1000);
}

function formatOutreachDate(value, lang) {
  if (!value) return lang === "de" ? "Datum unbekannt" : "Date unknown";
  const date = new Date(value);
  if (Number.isNaN(date.getTime())) return lang === "de" ? "Datum unbekannt" : "Date unknown";
  return date.toLocaleDateString(lang === "de" ? "de-DE" : "en-GB", { day: "2-digit", month: "2-digit", year: "numeric", timeZone: "Europe/Berlin" });
}

function outreachTaskDueAtIso(value) {
  if (!value) return null;
  const date = new Date(`${value}T09:00:00`);
  return Number.isNaN(date.getTime()) ? null : date.toISOString();
}

function outreachLocalDateTime() {
  const date = new Date();
  return new Date(date.getTime() - date.getTimezoneOffset() * 60000).toISOString().slice(0, 16);
}

function outreachDelayLabel(delay, lang) {
  const labels = lang === 'de' ? { hours: 'Stunden', days: 'Tage (24h)', business_days: 'Werktage (Mo–Fr)' } : { hours: 'hours', days: 'days (24h)', business_days: 'business days (Mon–Fri)' };
  return `${delay.value} ${labels[delay.unit] || delay.unit}`;
}

function CrmOutreachWorkspace({ user, lang, navigate, path, memberId }) {
  if (path === "/crm/outreach/import") return <CrmOutreachImport user={user} lang={lang} navigate={navigate} />;
  if (path === "/crm/outreach/new") return <CrmOutreachCreate user={user} lang={lang} navigate={navigate} />;
  if (path === "/crm/outreach/workflow") return <CrmOutreachWorkflowEditor lang={lang} navigate={navigate} />;
  if (memberId) return <CrmOutreachDetail user={user} lang={lang} navigate={navigate} memberId={memberId} />;
  return <CrmOutreachList user={user} lang={lang} navigate={navigate} memberId={memberId} />;
}

function CrmOutreachPreferences({ user, lang }) {
  const [form, setForm] = React.useState({ slackTarget: "", digestTime: "09:00", digestEnabled: false });
  const [agentDevices, setAgentDevices] = React.useState([]);
  const [agentName, setAgentName] = React.useState("");
  const [agentProvider, setAgentProvider] = React.useState("codex");
  const [newAgentCredential, setNewAgentCredential] = React.useState("");
  const [newAgentDeviceId, setNewAgentDeviceId] = React.useState("");
  const [credentialCopied, setCredentialCopied] = React.useState(false);
  const [runnerCommandCopied, setRunnerCommandCopied] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [pushBusy, setPushBusy] = React.useState(false);
  const [pushConfigured, setPushConfigured] = React.useState(null);
  const [pushActive, setPushActive] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [notice, setNotice] = React.useState("");

  React.useEffect(() => {
    let active = true;
    (async () => {
      try {
        const [saved, push, options] = await Promise.all([
          window.MesperOutreachDB.preferences({ user_id: user?.id, readOnly: true }),
          window.MesperOutreachDB.pushStatus ? window.MesperOutreachDB.pushStatus().catch(() => ({ configured: false })) : Promise.resolve({ configured: false }),
          window.MesperOutreachDB.options ? window.MesperOutreachDB.options().catch(() => ({ agentDevices: [] })) : Promise.resolve({ agentDevices: [] }),
        ]);
        if (active && saved) setForm({ slackTarget: saved.slackTarget || "", digestTime: saved.digestTime || "09:00", digestEnabled: Boolean(saved.digestEnabled) });
        if (active) setPushConfigured(Boolean(push?.configured));
        if (active) setAgentDevices(options?.agentDevices || []);
      } catch (loadError) { if (active) setError(loadError); }
      finally { if (active) setLoading(false); }
    })();
    return () => { active = false; };
  }, []);

  async function save() {
    setBusy(true); setError(null); setNotice("");
    try {
      await window.MesperOutreachDB.preferences({ user_id: user?.id, slack_target: form.slackTarget.trim() || null, digest_time: form.digestTime || "09:00", digest_enabled: form.digestEnabled, timezone: "Europe/Berlin" });
      setNotice(lang === "de" ? "Gespeichert. Es wurde keine Slack-Nachricht gesendet." : "Saved. No Slack message was sent.");
    } catch (saveError) { setError(saveError); }
    finally { setBusy(false); }
  }

  async function enablePush() {
    setPushBusy(true); setError(null); setNotice("");
    try {
      if (!pushConfigured) throw Object.assign(new Error(outreachDetailText(lang, "pushNotConfigured")), { code: "PUSH_NOT_CONFIGURED" });
      if (!navigator.serviceWorker || !window.MesperOutreachDB.pushSubscribe) throw new Error(lang === "de" ? "Browser-Push wird hier nicht unterstützt." : "Browser push is not supported here.");
      const status = await window.MesperOutreachDB.pushStatus();
      if (!status?.publicKey) throw Object.assign(new Error(outreachDetailText(lang, "pushNotConfigured")), { code: "PUSH_NOT_CONFIGURED" });
      const registration = await withOutreachTimeout(navigator.serviceWorker.register("/outreach-service-worker.js"), 10000, lang === "de" ? "Service Worker konnte nicht rechtzeitig gestartet werden." : "The service worker did not start in time.");
      const raw = atob(status.publicKey.replace(/-/g, "+").replace(/_/g, "/"));
      const key = Uint8Array.from(raw, (character) => character.charCodeAt(0));
      const activeRegistration = await withOutreachTimeout(navigator.serviceWorker.ready, 10000, lang === "de" ? "Service Worker wurde nicht aktiv." : "The service worker did not become active.");
      const subscription = await withOutreachTimeout(activeRegistration.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: key }), 12000, lang === "de" ? "Browser-Push konnte nicht rechtzeitig aktiviert werden." : "Browser push could not be enabled in time.");
      const serialized = subscription.toJSON();
      const normalizedSubscription = {
        endpoint: serialized.endpoint,
        p256dh: serialized.keys?.p256dh || serialized.p256dh,
        auth: serialized.keys?.auth || serialized.auth,
        expirationTime: serialized.expirationTime ?? null,
        userAgent: navigator.userAgent,
      };
      if (!normalizedSubscription.endpoint || !normalizedSubscription.p256dh || !normalizedSubscription.auth) throw Object.assign(new Error(lang === "de" ? "Browser-Push liefert keine gültigen Schlüssel." : "Browser push returned invalid keys."), { code: "PUSH_SUBSCRIPTION_INVALID" });
      await withOutreachTimeout(window.MesperOutreachDB.pushSubscribe(normalizedSubscription), 10000, lang === "de" ? "Browser-Push konnte nicht gespeichert werden." : "Browser push could not be saved.");
      setPushActive(true);
      setNotice(lang === "de" ? "Browser-Push aktiviert" : "Browser push enabled");
    } catch (pushError) { setError(pushError); }
    finally { setPushBusy(false); }
  }

  async function pairAgent() {
    const name = agentName.trim();
    if (!name) {
      setError({ message: lang === "de" ? "Gerätename erforderlich" : "Device name is required" });
      return;
    }
    setBusy(true); setError(null); setNotice(""); setCredentialCopied(false);
    try {
      const credential = createOutreachAgentCredential();
      const expiresAt = new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString();
      const deviceName = `${agentProvider === "claude" ? "Claude" : "Codex"} · ${name}`;
      const result = await window.MesperOutreachDB.agentControl("pair_agent_device", { name: deviceName, credential, expiresAt });
      setNewAgentCredential(credential);
      setNewAgentDeviceId(result.deviceId || "");
      setRunnerCommandCopied(false);
      setAgentName("");
      setAgentDevices((current) => [{ id: result.deviceId, deviceName, expiresAt: result.expiresAt || expiresAt, revokedAt: null, lastSeenAt: null }, ...current]);
      setNotice(outreachDetailText(lang, "agentPairSuccess"));
    } catch (pairError) { setError(pairError); }
    finally { setBusy(false); }
  }

  async function revokeAgent(device) {
    setBusy(true); setError(null); setNotice("");
    try {
      await window.MesperOutreachDB.agentControl("revoke_agent_device", { deviceId: device.id, reason: lang === "de" ? "Manuell widerrufen" : "Revoked manually" });
      setAgentDevices((current) => current.map((item) => item.id === device.id ? { ...item, revokedAt: new Date().toISOString() } : item));
      setNotice(outreachDetailText(lang, "agentRevokeSuccess"));
    } catch (revokeError) { setError(revokeError); }
    finally { setBusy(false); }
  }

  async function copyCredential() {
    if (!newAgentCredential) return;
    try { await navigator.clipboard.writeText(newAgentCredential); setCredentialCopied(true); } catch (_) { setCredentialCopied(false); }
  }

  async function copyRunnerCommand() {
    const command = outreachAgentRunnerCommand(agentProvider, newAgentDeviceId, newAgentCredential);
    if (!command) return;
    try { await navigator.clipboard.writeText(command); setRunnerCommandCopied(true); } catch (_) { setRunnerCommandCopied(false); }
  }

  return <section className="crm-outreach-card crm-outreach-preferences" aria-label={lang === "de" ? "Slack-Digest-Einstellungen" : "Slack digest settings"}>
    <div className="crm-outreach-card-header"><h2>{lang === "de" ? "Slack-Digest" : "Slack digest"}</h2><span>{lang === "de" ? "Nur interne Hinweise" : "Internal reminders only"}</span></div>
    <div className="crm-outreach-preferences-grid">
      <label className="crm-outreach-field"><span>{lang === "de" ? "Slack-Ziel" : "Slack target"}</span><input value={form.slackTarget} onChange={(event) => setForm((current) => ({ ...current, slackTarget: event.target.value }))} placeholder="C123456 oder U123456" disabled={loading || busy} /></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Tägliche Ortszeit" : "Daily local time"}</span><input type="time" value={form.digestTime} onChange={(event) => setForm((current) => ({ ...current, digestTime: event.target.value }))} disabled={loading || busy} /></label>
      <label className="crm-outreach-checkbox"><input type="checkbox" checked={form.digestEnabled} onChange={(event) => setForm((current) => ({ ...current, digestEnabled: event.target.checked }))} disabled={loading || busy} /> {lang === "de" ? "Digest aktivieren" : "Enable digest"}</label>
    </div>
    <p className="crm-outreach-muted">{lang === "de" ? "Es werden keine Channels erstellt. Speichern prüft das Ziel nicht und sendet nichts." : "No channels are created. Saving does not check the target or send anything."}</p>
    {error && <div className="crm-outreach-state crm-outreach-state-error" role="alert">{error.message || (lang === "de" ? "Einstellungen konnten nicht geladen werden." : "Could not load settings.")}</div>}
    {notice && <div className="crm-outreach-notice" role="status">{notice}</div>}
    <div className="crm-outreach-inline-actions">
      <button type="button" className="crm-outreach-button" onClick={save} disabled={loading || busy}>{busy ? (lang === "de" ? "Speichert…" : "Saving…") : (lang === "de" ? "Einstellungen speichern" : "Save settings")}</button>
      <button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={enablePush} disabled={loading || pushBusy || pushConfigured !== true}>{pushActive ? outreachDetailText(lang, "pushEnabled") : pushBusy ? (lang === "de" ? "Aktiviert…" : "Enabling…") : outreachDetailText(lang, "pushEnable")}</button>
    </div>
    {pushConfigured === false && <p className="crm-outreach-muted">{outreachDetailText(lang, "pushNotConfigured")}</p>}
    <div className="crm-outreach-agent-panel">
      <div className="crm-outreach-card-header"><h2>{outreachDetailText(lang, "agentDevices")}</h2><span>Codex / Claude lokal</span></div>
      <p className="crm-outreach-muted">{outreachDetailText(lang, "agentPairHint")}</p>
      <div className="crm-outreach-inline-actions">
        <label className="crm-outreach-field"><span>{outreachDetailText(lang, "agentProvider")}</span><select value={agentProvider} onChange={(event) => setAgentProvider(event.target.value)} disabled={loading || busy}><option value="codex">{outreachDetailText(lang, "agentCodex")}</option><option value="claude">{outreachDetailText(lang, "agentClaude")}</option></select></label>
        <label className="crm-outreach-field"><span>{outreachDetailText(lang, "agentName")}</span><input value={agentName} onChange={(event) => setAgentName(event.target.value)} disabled={loading || busy} /></label>
        <button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={pairAgent} disabled={loading || busy}>{outreachDetailText(lang, "agentPair")}</button>
      </div>
      {newAgentCredential && <div className="crm-outreach-agent-credential" role="status"><code>{newAgentCredential}</code><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={copyCredential}>{credentialCopied ? outreachDetailText(lang, "agentCredentialCopied") : outreachDetailText(lang, "agentCredential")}</button></div>}
      {newAgentCredential && newAgentDeviceId && <div className="crm-outreach-agent-credential"><span className="crm-outreach-muted">{outreachDetailText(lang, "runnerCommandHint")}</span><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={copyRunnerCommand}>{runnerCommandCopied ? outreachDetailText(lang, "runnerCommandCopied") : outreachDetailText(lang, "runnerCommand")}</button></div>}
      <div className="crm-outreach-agent-devices">{agentDevices.length === 0 ? <span className="crm-outreach-muted">{lang === "de" ? "Noch kein Gerät gepairt." : "No device paired yet."}</span> : agentDevices.map((device) => <div className="crm-outreach-agent-device" key={device.id}><div><strong>{device.deviceName || device.id}</strong><span>{outreachDetailText(lang, "agentExpires")} {formatOutreachDate(device.expiresAt, lang)} · {device.lastSeenAt ? `${outreachDetailText(lang, "agentLastSeen")} ${formatOutreachDate(device.lastSeenAt, lang)}` : outreachDetailText(lang, "agentNeverSeen")}</span></div>{device.revokedAt ? <span className="crm-outreach-status-chip">{outreachDetailText(lang, "agentRevoked")}</span> : <button type="button" className="crm-outreach-button crm-outreach-button-danger" onClick={() => revokeAgent(device)} disabled={busy}>{outreachDetailText(lang, "agentRevoke")}</button>}</div>)}</div>
    </div>
  </section>;
}

function outreachTimelineLabel(activity, lang) {
  if (!activity || activity.datePrecision === "unknown" || (!activity.occurredAt && !activity.occurredOn)) return lang === "de" ? "Datum unbekannt" : "Date unknown";
  if (activity.datePrecision === "day" || activity.occurredOn) return formatOutreachDate(activity.occurredOn, lang);
  const date = new Date(activity.occurredAt);
  if (Number.isNaN(date.getTime())) return lang === "de" ? "Datum unbekannt" : "Date unknown";
  return date.toLocaleString(lang === "de" ? "de-DE" : "en-GB", { dateStyle: "short", timeStyle: "short", timeZone: "Europe/Berlin" });
}

function CrmOutreachCreate({ user, lang, navigate }) {
  const [options, setOptions] = React.useState({ campaigns: [], contacts: [], companies: [] });
  const [form, setForm] = React.useState({ campaignId: "", contactId: "", companyId: "", fullName: "", companyName: "", email: "", linkedinUrl: "", domain: "", position: "" });
  const [loading, setLoading] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [notice, setNotice] = React.useState("");
  const t = (key) => outreachDetailText(lang, key);

  React.useEffect(() => {
    let active = true;
    (async () => {
      try {
        const result = await window.MesperOutreachDB.options();
        if (active) {
          const campaigns = result?.campaigns || [];
          setOptions({ campaigns, contacts: result?.contacts || [], companies: result?.companies || [] });
          setForm((current) => ({ ...current, campaignId: current.campaignId || campaigns.find((item) => item.native)?.id || campaigns[0]?.id || "" }));
        }
      } catch (loadError) { if (active) setError(loadError); }
      finally { if (active) setLoading(false); }
    })();
    return () => { active = false; };
  }, []);

  function update(key, value) { setForm((current) => ({ ...current, [key]: value })); }

  async function create() {
    if (!form.campaignId || (!form.contactId && !form.fullName.trim()) || (!form.contactId && !form.companyId && !form.companyName.trim()) || (form.contactId && !form.companyId)) {
      setError({ message: lang === "de" ? "Kampagne, Kontakt und Firma erforderlich" : "Campaign, contact and company are required" });
      return;
    }
    setBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId: null, expectedVersion: 1, action: "create_member", payload: {
        campaignId: form.campaignId,
        ...(form.companyId ? { companyId: form.companyId } : { company: { name: form.companyName.trim(), domain: form.domain.trim() || null } }),
        ...(form.contactId ? { contactId: form.contactId } : { contact: { fullName: form.fullName.trim(), email: form.email.trim() || null, linkedinUrl: form.linkedinUrl.trim() || null } }),
        research: form.position.trim() ? { position: form.position.trim() } : {},
      } });
      setNotice(t("created"));
      if (result?.memberId) navigate(`/crm/outreach/m/${result.memberId}`);
    } catch (createError) { setError(createError); }
    finally { setBusy(false); }
  }

  return <section className="crm-outreach-shell crm-outreach-create" aria-label={t("createTitle")}>
    <div className="crm-outreach-header"><div><button type="button" className="crm-outreach-back" onClick={() => navigate("/crm/outreach")}>← {t("back")}</button><h1 className="crm-outreach-title">{t("createTitle")}</h1><p className="crm-outreach-muted">{t("nativeDraftHint")}</p></div></div>
    {loading && <div className="crm-outreach-state" role="status">{lang === "de" ? "Lade Optionen…" : "Loading options…"}</div>}
    {!loading && <section className="crm-outreach-card"><div className="crm-outreach-form-grid">
      <label className="crm-outreach-field"><span>{t("campaign")}</span><select aria-label={t("campaign")} value={form.campaignId} onChange={(event) => update("campaignId", event.target.value)}><option value="">{t("noCampaign")}</option>{options.campaigns.map((campaign) => <option key={campaign.id} value={campaign.id}>{campaign.name}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Bestehender Kontakt" : "Existing contact"}</span><select aria-label={lang === "de" ? "Bestehender Kontakt" : "Existing contact"} value={form.contactId} onChange={(event) => { const contactId = event.target.value; const contact = options.contacts.find((item) => item.id === contactId); setForm((current) => ({ ...current, contactId, companyId: contact?.companyId || current.companyId })); }}><option value="">{lang === "de" ? "Neuen Kontakt anlegen" : "Create new contact"}</option>{options.contacts.map((contact) => <option key={contact.id} value={contact.id}>{contact.name}{contact.email ? ` · ${contact.email}` : ""}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{t("fullName")}</span><input aria-label={t("fullName")} value={form.fullName} onChange={(event) => update("fullName", event.target.value)} /></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Bestehende Firma" : "Existing company"}</span><select aria-label={lang === "de" ? "Bestehende Firma" : "Existing company"} value={form.companyId} onChange={(event) => update("companyId", event.target.value)}><option value="">{lang === "de" ? "Neue Firma anlegen" : "Create new company"}</option>{options.companies.map((company) => <option key={company.id} value={company.id}>{company.name}{company.domain ? ` · ${company.domain}` : ""}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{t("companyName")}</span><input aria-label={t("companyName")} value={form.companyName} onChange={(event) => update("companyName", event.target.value)} disabled={Boolean(form.companyId)} /></label>
      <label className="crm-outreach-field"><span>{t("email")}</span><input aria-label={t("email")} type="email" value={form.email} onChange={(event) => update("email", event.target.value)} /></label>
      <label className="crm-outreach-field"><span>{t("linkedinUrl")}</span><input aria-label={t("linkedinUrl")} type="url" value={form.linkedinUrl} onChange={(event) => update("linkedinUrl", event.target.value)} /></label>
      <label className="crm-outreach-field"><span>{t("domain")}</span><input aria-label={t("domain")} value={form.domain} onChange={(event) => update("domain", event.target.value)} /></label>
      <label className="crm-outreach-field"><span>{t("position")}</span><input aria-label={t("position")} value={form.position} onChange={(event) => update("position", event.target.value)} /></label>
    </div><div className="crm-outreach-inline-actions"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => navigate("/crm/outreach")} disabled={busy}>{t("cancel")}</button><button type="button" className="crm-outreach-button" onClick={create} disabled={busy || !options.campaigns.length}>{busy ? (lang === "de" ? "Speichert…" : "Saving…") : t("create")}</button></div></section>}
    {error && <div className="crm-outreach-state crm-outreach-state-error" role="alert">{error.message || (lang === "de" ? "Anlegen fehlgeschlagen" : "Could not create contact")}</div>}
    {notice && <div className="crm-outreach-notice" role="status">{notice}</div>}
  </section>;
}

function CrmOutreachDetail({ user, lang, navigate, memberId }) {
  const [data, setData] = React.useState(null);
  const [options, setOptions] = React.useState({ owners: [], campaigns: [] });
  const [drafts, setDrafts] = React.useState({ pitchText: "", followupText: "", replyText: "" });
  const [details, setDetails] = React.useState({ contact: {}, company: {}, research: {} });
  const [stageValue, setStageValue] = React.useState("review");
  const [connectionValue, setConnectionValue] = React.useState("unknown");
  const [acceptanceDate, setAcceptanceDate] = React.useState("");
  const [acceptanceEvidence, setAcceptanceEvidence] = React.useState("");
  const [acceptanceConfirmed, setAcceptanceConfirmed] = React.useState(false);
  const [stageReason, setStageReason] = React.useState("");
  const [loading, setLoading] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [notice, setNotice] = React.useState("");
  const [ownerId, setOwnerId] = React.useState("");
  const [taskTitle, setTaskTitle] = React.useState("");
  const [taskDueAt, setTaskDueAt] = React.useState("");
  const [sendOpen, setSendOpen] = React.useState(false);
  const [replyOpen, setReplyOpen] = React.useState(false);
  const [sendType, setSendType] = React.useState("pitch_sent");
  const [sentAt, setSentAt] = React.useState(outreachLocalDateTime);
  const pendingSend = React.useRef(null);
  const pendingLinkedinSend = React.useRef(null);
  const [replySentiment, setReplySentiment] = React.useState("neutral");
  const [replyBody, setReplyBody] = React.useState("");
  const [workflow, setWorkflow] = React.useState(emptyOutreachWorkflow);
  const [workflowLoading, setWorkflowLoading] = React.useState(true);
  const [workflowBusy, setWorkflowBusy] = React.useState(false);
  const [agentKind, setAgentKind] = React.useState("pitch");
  const [revokeReason, setRevokeReason] = React.useState("");

  React.useEffect(() => {
    let active = true;
    setLoading(true); setError(null); setNotice("");
    (async () => {
      try {
        const [result, nativeOptions, workflowResult] = await Promise.all([
          window.MesperOutreachDB.detail(memberId),
          window.MesperOutreachDB.options().catch(() => ({ owners: [], campaigns: [] })),
          window.MesperOutreachDB.workflow ? window.MesperOutreachDB.workflow(memberId) : Promise.resolve(emptyOutreachWorkflow()),
        ]);
        if (!active) return;
        const merged = { ...result, owners: result.owners?.length ? result.owners : (nativeOptions.owners || []) };
        setData(merged);
        setOptions(nativeOptions || { owners: [], campaigns: [] });
        const replyRevision = workflowRevision(workflowResult || emptyOutreachWorkflow(), "reply");
        setDrafts({ pitchText: result.member?.pitchText || "", followupText: result.member?.followupText || "", replyText: replyRevision?.body || "" });
        setStageValue(result.member?.stage || "review");
        setConnectionValue(result.member?.connectionState || "unknown");
        setDetails({
          contact: { first: result.contact?.first || "", last: result.contact?.last || "", title: result.contact?.title || "", email: result.contact?.email || "", phone: result.contact?.phone || "", linkedinUrl: result.contact?.linkedinUrl || "" },
          company: { name: result.company?.name || "", domain: result.company?.domain || "", website: result.company?.website || "", industry: result.company?.industry || "", size: result.company?.size || "", linkedinUrl: result.company?.linkedinUrl || "" },
          research: { ...(result.member?.research || {}) },
        });
        setOwnerId(result.member?.ownerId || "");
        setWorkflow(workflowResult || emptyOutreachWorkflow());
      } catch (loadError) { if (active) setError(loadError); }
      finally { if (active) { setLoading(false); setWorkflowLoading(false); } }
    })();
    return () => { active = false; };
  }, [memberId]);

  if (loading) return <section className="crm-outreach-shell"><div className="crm-outreach-state" role="status">{lang === "de" ? "Lade Kontaktdetail…" : "Loading contact detail…"}</div></section>;
  if (!data) return <section className="crm-outreach-shell"><div className="crm-outreach-state crm-outreach-state-error" role="alert"><strong>{error?.message || (lang === "de" ? "Kontakt nicht gefunden" : "Contact not found")}</strong><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => navigate("/crm/outreach")}>{lang === "de" ? "Zurück" : "Back"}</button></div></section>;

  const member = data.member || {};
  const contact = data.contact || {};
  const company = data.company || {};
  const ot = (key) => outreachDetailText(lang, key);
  const research = member.research || {};
  const linkedinUrl = typeof CrmOutreachEngine === "object" && CrmOutreachEngine?.safeExternalUrl ? CrmOutreachEngine.safeExternalUrl(member.linkedInUrl || contact.linkedinUrl || research.linkedinUrl) : null;
  const researchWebsite = typeof CrmOutreachEngine === "object" && CrmOutreachEngine?.safeExternalUrl ? CrmOutreachEngine.safeExternalUrl(research.website) : null;
  const researchRows = [
    [lang === "de" ? "Position" : "Position", research.position],
    [lang === "de" ? "Mitarbeitende (SN)" : "Employees (SN)", research.employeeEstimate],
    [lang === "de" ? "Jahresumsatz (Schätzung)" : "Estimated annual revenue", research.estimatedRevenue],
    [lang === "de" ? "Branche" : "Industry", research.industry],
  ].filter(([, value]) => value);
  const replyRevision = workflowRevision(workflow, "reply");
  const sequenceConfig = (workflow.sequenceTasks || []).find(t => t.status === 'open' && t.outreachWorkflow)?.outreachWorkflow
    || (workflow.sequenceActivities || []).find(a => a.metadata?.workflowSnapshot)?.metadata.workflowSnapshot
    || (workflow.sequenceTasks || []).find(t => t.outreachWorkflow && ['prepare', 'follow_up'].includes(t.outreachPurpose))?.outreachWorkflow
    || options.campaigns?.find(c => c.id === member.campaignId)?.settings?.workflow;
  const sequenceSends = (workflow.sequenceActivities || []).filter(a => a.type === 'linkedin' && a.direction === 'outbound' && (['pitch', 'followup'].includes(a.metadata?.kind) || ['Pitch gesendet', 'Follow-up gesendet'].includes(a.subject))).map(a => ({ kind: a.metadata?.kind || (a.subject === 'Pitch gesendet' ? 'pitch' : 'followup'), occurredAt: a.occurredAt }));
  const configuredSequence = sequenceConfig?.enabled === true && window.MesperOutreachWorkflow?.validate(sequenceConfig).length === 0;
  const followupIndex = sequenceSends.filter(s => s.kind === 'followup').length;
  const followupStepId = configuredSequence ? sequenceConfig.followups[followupIndex]?.id : null;
  const followupRevision = workflowRevision(workflow, 'followup');
  const needsStepBinding = Boolean(followupStepId && drafts.followupText && followupRevision?.recipientSnapshot?.workflowStepId !== followupStepId);
  const isDirty = drafts.pitchText !== (member.pitchText || "") || drafts.followupText !== (member.followupText || "") || drafts.replyText !== (replyRevision?.body || "") || needsStepBinding;
  const commandError = error?.code === "VERSION_CONFLICT" ? (lang === "de" ? "Zwischenzeitlich geändert" : "Changed in the meantime") : error?.message;
  const currentRevision = workflowRevision(workflow, agentKind);
  const currentReview = currentRevision ? workflowReview(workflow, currentRevision.id) : null;
  const currentApproval = currentRevision ? workflowApproval(workflow, currentRevision.id) : null;
  const currentPreparation = currentRevision ? workflowPreparation(workflow, currentRevision.id) : null;
  const openTasks = (data.tasks || []).filter((task) => task.status === "open").sort((a, b) => {
    if (!a.dueAt) return 1;
    if (!b.dueAt) return -1;
    return new Date(a.dueAt) - new Date(b.dueAt);
  });
  const nextTask = openTasks[0] || null;
  const connectionAnchor = (workflow.sequenceTasks || []).find(task => task.outreachConnectionAt);
  const workflowStep = member.executionState !== "active"
    ? (lang === "de" ? "Entwurf: Erst nach Owner und erster Aufgabe aktivieren" : "Draft: activate only with an owner and first task")
    : ["paused", "closed"].includes(member.stage)
      ? (lang === "de" ? "Ansprache gestoppt" : "Outreach stopped")
      : member.connectionState === "pending"
        ? (lang === "de" ? "Auf Annahme der Vernetzungsanfrage warten" : "Wait for connection acceptance")
        : member.connectionState === "connected" && ["review", "ready", "connecting"].includes(member.stage)
          ? (lang === "de" ? "Pitch prüfen, freigeben und senden" : "Review, approve and send the pitch")
          : nextTask?.title || (lang === "de" ? "Nächste Aktion und Fälligkeit prüfen" : "Review next action and due date");

  async function refreshWorkflow() {
    if (!window.MesperOutreachDB.workflow) return;
    const next = await window.MesperOutreachDB.workflow(memberId);
    setWorkflow(next || emptyOutreachWorkflow());
  }

  async function saveDrafts() {
    setBusy(true); setError(null); setNotice("");
    try {
      let expectedVersion = member.version || 1;
      let result = null;
      const recipientSnapshot = { contactId: contact.id || member.contactId || null, linkedinUrl: linkedinUrl || null };
      const revisions = [
        ["pitch", drafts.pitchText, member.pitchText || ""],
        ["followup", drafts.followupText, member.followupText || ""],
        ["reply", drafts.replyText, replyRevision?.body || ""],
      ];
      for (const [kind, body, currentBody] of revisions) {
        if (body === currentBody && !(kind === 'followup' && needsStepBinding)) continue;
        result = await window.MesperOutreachDB.command({ memberId, expectedVersion, action: "save_revision", payload: { kind, body, recipientSnapshot: { ...recipientSnapshot, ...(kind === 'followup' && followupStepId ? { workflowStepId: followupStepId } : {}) }, source: "human" } });
        expectedVersion = result.version || expectedVersion + 1;
      }
      setData((current) => ({ ...current, member: { ...current.member, version: expectedVersion, pitchText: drafts.pitchText, followupText: drafts.followupText } }));
      await refreshWorkflow().catch(() => {});
      setNotice(lang === "de" ? "Gespeichert" : "Saved");
    } catch (saveError) { setError(saveError); }
    finally { setBusy(false); }
  }

  function updateDetails(section, key, value) {
    setDetails((current) => ({ ...current, [section]: { ...current[section], [key]: value } }));
  }

  async function saveDetails() {
    setBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "edit_details", payload: details });
      setData((current) => ({ ...current, member: { ...current.member, version: result.version || current.member.version } }));
      setNotice(lang === "de" ? "Kontakt, Firma und Research gespeichert" : "Contact, company and research saved");
    } catch (saveError) { setError(saveError); }
    finally { setBusy(false); }
  }

  async function saveStatus() {
    if ((stageValue === "paused" || stageValue === "closed") && !stageReason.trim()) {
      setError({ message: lang === "de" ? "Begründung erforderlich" : "A reason is required" });
      return;
    }
    setBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "set_stage", payload: { stage: stageValue, ...(stageReason.trim() ? { reason: stageReason.trim() } : {}) } });
      setData((current) => ({ ...current, member: { ...current.member, stage: stageValue, version: result.version || current.member.version } }));
      setNotice(lang === "de" ? "Status gespeichert" : "Status saved");
    } catch (saveError) { setError(saveError); }
    finally { setBusy(false); }
  }

  async function saveConnection() {
    if (connectionValue === "connected") {
      setError({ message: lang === "de" ? "Annahme unten mit Datum und Beleg bestätigen" : "Confirm acceptance below with date and evidence" });
      return;
    }
    setBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "set_connection", payload: { connectionState: connectionValue } });
      setData((current) => ({ ...current, member: { ...current.member, connectionState: connectionValue, version: result.version || current.member.version } }));
      setNotice(lang === "de" ? "Vernetzung gespeichert" : "Connection saved");
    } catch (saveError) { setError(saveError); }
    finally { setBusy(false); }
  }

  async function recordAcceptance() {
    if (!acceptanceConfirmed || !acceptanceDate || !/^https:\/\/\S+$/i.test(acceptanceEvidence.trim())) {
      setError({ message: lang === "de" ? "Annahmetag, HTTPS-Beleg und Bestätigung erforderlich" : "Acceptance date, HTTPS evidence and confirmation required" });
      return;
    }
    setBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "record_connection_acceptance", payload: { acceptedOn: acceptanceDate, evidenceUrl: acceptanceEvidence.trim() } });
      const fresh = await window.MesperOutreachDB.detail(memberId);
      setData((current) => ({ ...current, ...fresh }));
      setConnectionValue("connected"); setStageValue(result.stage);
      setAcceptanceConfirmed(false);
      setNotice(lang === "de" ? "Annahme dokumentiert. Kein LinkedIn-Versand erfolgt." : "Acceptance recorded. No LinkedIn message was sent.");
    } catch (saveError) { setError(saveError); }
    finally { setBusy(false); }
  }

  async function requestAgentJob(jobType) {
    const revision = jobType === "review" ? workflowRevision(workflow, agentKind) : null;
    if (jobType === "review" && !revision) {
      setError({ message: ot("noRevision") });
      return;
    }
    setWorkflowBusy(true); setError(null); setNotice("");
    try {
      const contextHash = revision?.contextHash || ("manual-" + memberId + "-" + agentKind + "-" + (member.version || 1));
      const buildSnapshot = typeof CrmOutreachEngine === "object" && CrmOutreachEngine?.buildAgentContextSnapshot;
      if (typeof buildSnapshot !== "function") throw new Error("AGENT_CONTEXT_UNAVAILABLE");
      const contextSnapshot = buildSnapshot({
        member,
        contact,
        company,
        research,
        message: revision
          ? { kind: agentKind, revisionId: revision.id, body: revision.body || "", contextHash: revision.contextHash || contextHash }
          : { kind: agentKind, body: agentKind === "pitch" ? drafts.pitchText : agentKind === "followup" ? drafts.followupText : drafts.replyText, contextHash },
        tasks: data.tasks || [],
      });
      const result = await window.MesperOutreachDB.command({
        memberId,
        expectedVersion: member.version || 1,
        action: "enqueue_agent_job",
        payload: {
          jobType,
          messageKind: jobType === "draft" ? agentKind : undefined,
          revisionId: revision?.id,
          contextHash,
          recipientSnapshot: { contactId: contact.id || member.contactId || null, linkedinUrl: linkedinUrl || null, ...(agentKind === 'followup' && followupStepId ? { workflowStepId: followupStepId } : {}) },
          contextSnapshot,
        },
      });
      setData((current) => ({ ...current, member: { ...current.member, version: result.version || current.member.version } }));
      setNotice(ot("agentJobRequested"));
    } catch (jobError) { setError(jobError); }
    finally { setWorkflowBusy(false); }
  }

  async function approveCurrentRevision() {
    if (!currentRevision || !currentReview || currentReview.source !== "agent") {
      setError({ message: lang === "de" ? "Agent-Review für die aktuelle Revision erforderlich" : "An agent review for the current revision is required" });
      return;
    }
    setWorkflowBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "approve_revision", payload: { revisionId: currentRevision.id } });
      setData((current) => ({ ...current, member: { ...current.member, version: result.version || current.member.version } }));
      setWorkflow((current) => ({ ...current, approvals: [{ id: result.approvalId || "pending-approval", revisionId: currentRevision.id, memberId, revokedAt: null }, ...(current.approvals || [])] }));
      setNotice(ot("approvalSaved"));
    } catch (approvalError) { setError(approvalError); }
    finally { setWorkflowBusy(false); }
  }

  async function revokeCurrentApproval() {
    if (!currentRevision || !currentApproval || !revokeReason.trim()) {
      setError({ message: lang === "de" ? "Widerrufsgrund erforderlich" : "A revocation reason is required" });
      return;
    }
    setWorkflowBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "revoke_approval", payload: { revisionId: currentRevision.id, reason: revokeReason.trim() } });
      setData((current) => ({ ...current, member: { ...current.member, version: result.version || current.member.version } }));
      setWorkflow((current) => ({ ...current, approvals: (current.approvals || []).map((approval) => approval.id === currentApproval.id ? { ...approval, revokedAt: new Date().toISOString(), revokeReason: revokeReason.trim() } : approval) }));
      setNotice(lang === "de" ? "Freigabe widerrufen" : "Approval revoked");
    } catch (revokeError) { setError(revokeError); }
    finally { setWorkflowBusy(false); }
  }

  async function queueLinkedinSend() {
    if (!currentRevision || !currentApproval || agentKind === 'reply') return;
    setWorkflowBusy(true); setError(null); setNotice('');
    try {
      const input = { memberId, expectedVersion: member.version || 1, action: 'queue_linkedin_send', payload: { revisionId: currentRevision.id } };
      const key = JSON.stringify(input);
      if (pendingLinkedinSend.current?.key !== key) pendingLinkedinSend.current = { key, command: { ...input, operationId: crypto.randomUUID() } };
      await window.MesperOutreachDB.command(pendingLinkedinSend.current.command);
      pendingLinkedinSend.current = null;
      setNotice(lang === 'de' ? 'Versand beauftragt. Chrome sendet frühestens zur Fälligkeit, sofern alle Prüfungen bestehen. Queue im Workflow prüfen.' : 'Send queued. Chrome sends no earlier than the due time, only if all checks pass. Check the queue in Workflow.');
    } catch (queueError) { setError(queueError); }
    finally { setWorkflowBusy(false); }
  }

  async function prepareCurrentSend() {
    if (agentKind === "reply") {
      setError({ message: lang === "de" ? "Reply ist ein Draft und wird nicht als LinkedIn-Versand vorbereitet" : "Reply is a draft and cannot be prepared as a LinkedIn send" });
      return;
    }
    if (!currentRevision || !currentApproval) {
      setError({ message: lang === "de" ? "Menschliche Freigabe erforderlich" : "Human approval is required" });
      return;
    }
    setWorkflowBusy(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "prepare_send", payload: { revisionId: currentRevision.id, kind: agentKind } });
      setData((current) => ({ ...current, member: { ...current.member, version: result.version || current.member.version } }));
      setWorkflow((current) => ({ ...current, preparations: [{ id: result.preparationId || "pending-preparation", revisionId: currentRevision.id, memberId, kind: agentKind, expiresAt: result.expiresAt || new Date(Date.now() + 600000).toISOString(), usedAt: null }, ...(current.preparations || [])] }));
      setNotice(ot("sendPrepared"));
    } catch (prepareError) { setError(prepareError); }
    finally { setWorkflowBusy(false); }
  }

  async function activate() {
    if (!ownerId || !taskTitle.trim() || !taskDueAt) { setError({ message: lang === "de" ? "Owner und erste Aufgabe erforderlich" : "Owner and first task required" }); return; }
    setBusy(true); setError(null);
    const dueAt = outreachTaskDueAtIso(taskDueAt);
    if (!dueAt) { setError({ message: lang === "de" ? "Gültige Fälligkeit erforderlich" : "A valid due date is required" }); setBusy(false); return; }
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "activate", payload: { ownerId, task: { title: taskTitle.trim(), kind: "linkedin", dueAt, purpose: "manual" } } });
      setNotice(lang === "de" ? "Aktiviert" : "Activated");
      setData((current) => ({ ...current, member: { ...current.member, ...(result.member || {}), version: result.version || result.member?.version || current.member.version, executionState: "active", ownerId } }));
    }
    catch (actionError) { setError(actionError); }
    finally { setBusy(false); }
  }

  async function markSent() {
    const sendKind = sendType === "followup_sent" ? "followup" : "pitch";
    const sendRevision = workflowRevision(workflow, sendKind);
    const sendPreparation = workflowPreparation(workflow, sendRevision?.id);
    if (!sendRevision || !sendPreparation) {
      setError({ message: lang === "de" ? "Aktuelle Revision muss menschlich freigegeben und vorbereitet sein" : "The current revision must be human-approved and prepared" });
      return;
    }
    const nextDueAt = outreachTaskDueAtIso(taskDueAt);
    if (!configuredSequence && (!taskTitle.trim() || !nextDueAt)) { setError({ message: lang === "de" ? "Nächste Aktion mit Fälligkeit erforderlich" : "A next step with a due date is required" }); return; }
    if (!sentAt || Number.isNaN(new Date(sentAt).getTime())) { setError({ message: lang === 'de' ? 'Gültiger Versandzeitpunkt erforderlich' : 'A valid send time is required' }); return; }
    setBusy(true); setError(null);
    try {
      const input = { memberId, expectedVersion: member.version || 1, action: "mark_sent", payload: { kind: sendKind, revisionId: sendRevision.id, preparationId: sendPreparation.id, occurredAt: new Date(sentAt).toISOString(), ...(!configuredSequence ? { nextTask: { title: taskTitle.trim(), kind: "linkedin", dueAt: nextDueAt, purpose: "follow_up" } } : {}) } };
      const key = JSON.stringify(input);
      if (pendingSend.current?.key !== key) pendingSend.current = { key, command: { ...input, operationId: crypto.randomUUID() } };
      const result = await window.MesperOutreachDB.command(pendingSend.current.command);
      setData((current) => ({ ...current, member: { ...current.member, ...(result.member || {}), version: result.version || result.member?.version || current.member.version } }));
      pendingSend.current = null; setSendOpen(false); setNotice(lang === "de" ? "Gesendet" : "Sent");
      if (configuredSequence) {
        try {
          const fresh = await window.MesperOutreachDB.detail(memberId);
          setData(fresh); setStageValue(fresh.member?.stage || member.stage); await refreshWorkflow();
        } catch (reloadError) { setError({ message: lang === 'de' ? 'Versand ist dokumentiert. Aktualisierung fehlgeschlagen. Neu laden, nicht erneut bestätigen.' : 'Sending is recorded. Refresh failed. Reload, do not confirm again.' }); }
      }
    }
    catch (actionError) { setError(actionError); }
    finally { setBusy(false); }
  }

  async function logReply() {
    const nextDueAt = outreachTaskDueAtIso(taskDueAt);
    if (!taskTitle.trim() || !nextDueAt) { setError({ message: lang === "de" ? "Nächste Aktion mit Fälligkeit erforderlich" : "A next step with a due date is required" }); return; }
    setBusy(true); setError(null);
    try {
      const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action: "log_reply", payload: { body: replyBody.trim() || null, sentiment: replySentiment, occurredAt: new Date().toISOString(), nextTask: { title: taskTitle.trim(), kind: "general", dueAt: nextDueAt, purpose: "reply" } } });
      setData((current) => ({ ...current, member: { ...current.member, ...(result.member || {}), version: result.version || result.member?.version || current.member.version } }));
      setReplyOpen(false); setNotice(lang === "de" ? "Antwort erfasst" : "Reply logged");
    }
    catch (actionError) { setError(actionError); }
    finally { setBusy(false); }
  }

  async function closeWithReason(action, reason) {
    setBusy(true); setError(null);
    try { const result = await window.MesperOutreachDB.command({ memberId, expectedVersion: member.version || 1, action, payload: { reason } }); const nextStage = action === "close" ? "closed" : "paused"; setData((current) => ({ ...current, member: { ...current.member, stage: nextStage, version: result.version || current.member.version } })); setStageValue(nextStage); setNotice(action === "close" ? (lang === "de" ? "Ansprache beendet" : "Outreach closed") : (lang === "de" ? "Kontakt pausiert" : "Contact paused")); }
    catch (actionError) { setError(actionError); }
    finally { setBusy(false); }
  }

  async function copyText(value) {
    try { await navigator.clipboard.writeText(value || ""); setNotice(lang === "de" ? "Kopiert" : "Copied"); }
    catch (_) { setError({ message: lang === "de" ? "Kopieren fehlgeschlagen" : "Copy failed" }); }
  }

  function openLinkedIn() {
    if (!linkedinUrl) { setError({ message: lang === "de" ? "Keine gültige LinkedIn-URL" : "No valid LinkedIn URL" }); return; }
    window.open(linkedinUrl, "_blank", "noopener,noreferrer");
  }

  async function exportCompanyData() {
    if (!window.MesperDB?.crmExportCompany) return;
    setBusy(true); setError(null);
    try {
      const dump = await window.MesperDB.crmExportCompany(company.id);
      const blob = new Blob([JSON.stringify(dump, null, 2)], { type: "application/json" });
      const url = URL.createObjectURL(blob);
      const link = document.createElement("a");
      link.href = url;
      link.download = "crm-" + (company.domain || company.name || company.id).replace(/[^a-z0-9]+/gi, "-").toLowerCase() + ".json";
      document.body.appendChild(link); link.click(); link.remove();
      setTimeout(() => URL.revokeObjectURL(url), 1000);
      setNotice(lang === "de" ? "CRM-Export erstellt" : "CRM export created");
    } catch (exportError) { setError(exportError); }
    finally { setBusy(false); }
  }

  async function deleteCompanyData() {
    if (!window.MesperDB?.crmDeleteCompany || !window.confirm(lang === "de" ? "Firma und verknüpfte Outreach-Daten wirklich löschen?" : "Delete the company and linked outreach data?")) return;
    setBusy(true); setError(null);
    try {
      await window.MesperDB.crmDeleteCompany(company.id);
      navigate("/crm/outreach");
    } catch (deleteError) { setError(deleteError); setBusy(false); }
  }

  return <section className="crm-outreach-shell crm-outreach-detail">
    <div className="crm-outreach-header"><div><button type="button" className="crm-outreach-back" onClick={() => navigate("/crm/outreach")}>← {ot("back")}</button><h1 className="crm-outreach-title">{typeof CrmOutreachEngine === "object" && CrmOutreachEngine?.contactDisplayName ? CrmOutreachEngine.contactDisplayName(contact) : outreachContactLabel(member)}</h1><p className="crm-outreach-muted">{company.name || ot("unknownBrand")} · {outreachStageLabel(member.stage, lang)} · {outreachConnectionLabel(member.connectionState, lang)}</p></div><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => navigate(`/crm/c/${company.id || ""}`)}>{ot("openCompany")}</button></div>
    {error && <div className="crm-outreach-state crm-outreach-state-error" role="alert"><strong>{commandError}</strong></div>}
    {notice && <div className="crm-outreach-notice" role="status">{notice}</div>}
    <section className="crm-outreach-workflow" aria-label={lang === "de" ? "Nächster Outreach-Schritt" : "Next outreach step"}>
      <div className="crm-outreach-workflow-copy">
        <span className="crm-outreach-workflow-eyebrow">{lang === "de" ? "Nächster Schritt" : "Next step"}</span>
        <h2>{workflowStep}</h2>
        <p>{nextTask ? `${nextTask.title} · ${nextTask.dueAt ? outreachTimelineLabel({ occurredAt: nextTask.dueAt }, lang) : (lang === "de" ? "Fälligkeit fehlt" : "Due date missing")}` : (lang === "de" ? "Noch keine offene Aufgabe mit Fälligkeit" : "No open task with a due date")}</p>
      </div>
      <div className="crm-outreach-workflow-actions">
        {linkedinUrl ? <a className="crm-outreach-button" href={linkedinUrl} target="_blank" rel="noopener noreferrer">{lang === "de" ? "Profil auf LinkedIn öffnen" : "Open LinkedIn profile"}</a> : <button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => document.querySelector('.crm-outreach-detail input[aria-label="LinkedIn-URL"]')?.focus()}>{lang === "de" ? "LinkedIn-Profil hinterlegen" : "Add LinkedIn profile"}</button>}
        <span>{lang === "de" ? "Chrome-Anbindung im Workflow koppeln. Automatik braucht das passende angemeldete LinkedIn-Konto und einen wachen Rechner." : "Pair the Chrome connection in Workflow. Automation requires the matching signed-in LinkedIn account and an awake computer."}</span>
      </div>
    </section>
    {sequenceConfig && <section className="crm-outreach-card crm-workflow-contact" aria-label={lang === 'de' ? 'Kontakt-Workflow' : 'Contact workflow'}><div className="crm-outreach-card-header"><h2>LinkedIn Workflow</h2><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => navigate('/crm/outreach/workflow')}>{lang === 'de' ? 'Workflow bearbeiten' : 'Edit workflow'}</button></div><p className="crm-outreach-muted">{configuredSequence ? (lang === 'de' ? 'Nächste Schritte werden nach bestätigtem Versand automatisch geplant. Versand manuell oder über gekoppelte Chrome-Queue.' : 'Next steps are scheduled automatically after confirmed sending. Send manually or through the paired Chrome queue.') : (lang === 'de' ? 'Dieser Plan ist für neue Strecken ausgeschaltet.' : 'This plan is disabled for new sequences.')}</p>{configuredSequence && <ol><li>{lang === 'de' ? 'Pitch' : 'Pitch'}: {outreachDelayLabel(sequenceConfig.pitch.delay, lang)} · {lang === 'de' ? 'menschliche Freigabe' : 'human approval'}</li>{sequenceConfig.followups.map((s, i) => <li key={s.id}>{s.label} · {outreachDelayLabel(s.delay, lang)} · {s.approval === 'preapproved' ? (lang === 'de' ? 'konkrete Vorabfreigabe' : 'specific pre-approval') : (lang === 'de' ? 'einzeln freigeben' : 'approve each time')}{i === followupIndex ? (lang === 'de' ? ' · nächster Follow-up' : ' · next follow-up') : ''}</li>)}</ol>}<p className="crm-outreach-muted">{lang === 'de' ? 'Antwort, Meeting, Stop und Kill Switch haben Vorrang. Laufende Aufgaben behalten ihren gespeicherten Plan.' : 'Reply, meeting, stop and kill switch take priority. Existing tasks retain their saved plan.'}</p></section>}
    {connectionAnchor && <p className="crm-outreach-notice" role="status">{connectionAnchor.outreachConnectionBasis === 'observed' ? (lang === 'de' ? 'Erstmals als vernetzt erkannt' : 'First detected as connected') : (lang === 'de' ? 'Belegter Annahmezeitpunkt' : 'Verified acceptance time')}: {outreachTimelineLabel({ occurredAt: connectionAnchor.outreachConnectionAt }, lang)}. {connectionAnchor.outreachConnectionBasis === 'observed' && (lang === 'de' ? 'Fristen laufen ab dieser Erkennung, nicht ab einem unbekannten tatsächlichen Annahmezeitpunkt.' : 'Deadlines run from this detection, not an unknown actual acceptance time.')}</p>}
    <div className="crm-outreach-detail-grid">
      <div className="crm-outreach-detail-main">
        <section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{ot("drafts")}</h2><span className={isDirty ? "crm-outreach-dirty" : ""}>{isDirty ? ot("unsaved") : ot("saved")}</span></div><label className="crm-outreach-field"><span>{ot("pitch")}</span><textarea aria-label={ot("pitch")} value={drafts.pitchText} onChange={(event) => setDrafts((current) => ({ ...current, pitchText: event.target.value }))} rows="7" /></label><div className="crm-outreach-inline-actions"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => copyText(drafts.pitchText)} disabled={busy}>{ot("copy")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={openLinkedIn} disabled={!linkedinUrl || busy}>{ot("linkedin")}</button></div><label className="crm-outreach-field"><span>{ot("followup")}</span><textarea aria-label={ot("followup")} value={drafts.followupText} onChange={(event) => setDrafts((current) => ({ ...current, followupText: event.target.value }))} rows="5" /></label><label className="crm-outreach-field"><span>{ot("reply")}</span><textarea aria-label={ot("reply")} value={drafts.replyText} onChange={(event) => setDrafts((current) => ({ ...current, replyText: event.target.value }))} rows="5" /></label><button type="button" className="crm-outreach-button" onClick={saveDrafts} disabled={busy || !isDirty}>{busy ? ot("saving") : ot("save")}</button></section>
        <section className="crm-outreach-card crm-outreach-ai-card" aria-label={ot("aiAssistant")}><div className="crm-outreach-card-header"><h2>{ot("aiAssistant")}</h2><span>{lang === "de" ? "Human in the loop" : "Human in the loop"}</span></div><p className="crm-outreach-muted">{ot("aiLocalHint")}</p><div className="crm-outreach-form-grid"><label className="crm-outreach-field"><span>{ot("aiKind")}</span><select aria-label={ot("aiKind")} value={agentKind} onChange={(event) => setAgentKind(event.target.value)}><option value="pitch">{ot("pitch")}</option><option value="followup">{ot("followup")}</option><option value="reply">{ot("reply")}</option></select></label></div><div className="crm-outreach-inline-actions"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => requestAgentJob("draft")} disabled={workflowBusy}>{ot("aiDraft")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => requestAgentJob("review")} disabled={workflowBusy || !currentRevision}>{ot("aiReview")}</button></div>{workflowLoading ? <div className="crm-outreach-muted">{lang === "de" ? "Lade Message-Workflow…" : "Loading message workflow…"}</div> : !currentRevision ? <div className="crm-outreach-muted">{ot("noRevision")}</div> : <div className="crm-outreach-ai-review"><div className="crm-outreach-card-header"><strong>{ot("revision")} {currentRevision.revisionNo || "?"} · {ot(agentKind)}</strong><span>{currentRevision.source === "agent" ? ot("sourceAgent") : ot("sourceHuman")}</span></div><p className="crm-outreach-ai-body">{currentRevision.body || ""}</p>{currentReview ? <div className="crm-outreach-ai-findings"><strong>{ot("reviewSummary")}</strong><p>{currentReview.summary || ot("noReview")}</p>{Array.isArray(currentReview.findings) && currentReview.findings.length > 0 && <ul>{currentReview.findings.map((finding, index) => <li key={index}>{typeof finding === "string" ? finding : JSON.stringify(finding)}</li>)}</ul>}</div> : <p className="crm-outreach-muted">{ot("noReview")}</p>}{currentApproval ? <div className="crm-outreach-notice">{ot("approved")}</div> : <button type="button" className="crm-outreach-button" onClick={approveCurrentRevision} disabled={workflowBusy || !currentReview || currentReview.source !== "agent"}>{ot("approve")}</button>}{currentApproval && <><label className="crm-outreach-field"><span>{ot("revokeReason")}</span><input aria-label={ot("revokeReason")} value={revokeReason} onChange={(event) => setRevokeReason(event.target.value)} /></label><div className="crm-outreach-inline-actions"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={revokeCurrentApproval} disabled={workflowBusy}>{ot("revokeApproval")}</button><button type="button" className="crm-outreach-button" onClick={queueLinkedinSend} disabled={workflowBusy || agentKind === "reply"}>{lang === "de" ? "Über LinkedIn senden" : "Send via LinkedIn"}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={prepareCurrentSend} disabled={workflowBusy || agentKind === "reply"}>{ot("prepareSend")}</button></div></>}{currentPreparation && <div className="crm-outreach-notice">{ot("sendPrepared")} · {ot("expires")} {formatOutreachDate(currentPreparation.expiresAt, lang)} · {ot("linkedin")}</div>}</div>}</section>
        <section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{ot("actions")}</h2><span>{member.executionState === "active" ? ot("active") : ot("notActive")}</span></div><div className="crm-outreach-action-grid"><button type="button" className="crm-outreach-button" onClick={() => { if (!pendingSend.current) setSentAt(outreachLocalDateTime()); setSendOpen(true); }} disabled={busy}>{ot("markSent")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => setReplyOpen(true)} disabled={busy}>{ot("logReply")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => closeWithReason("close", "no_need")} disabled={busy}>{ot("noNeed")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => closeWithReason("pause", "contact_stop")} disabled={busy}>{ot("stopContact")}</button></div></section>
        <section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{ot("status")}</h2><span>{outreachStageLabel(stageValue, lang)}</span></div><div className="crm-outreach-form-grid"><label className="crm-outreach-field"><span>{lang === "de" ? "Outreach-Status" : "Outreach stage"}</span><select aria-label={lang === "de" ? "Outreach-Status" : "Outreach stage"} value={stageValue} onChange={(event) => setStageValue(event.target.value)}>{Object.keys(OUTREACH_STAGE_LABELS).map((stage) => <option key={stage} value={stage}>{outreachStageLabel(stage, lang)}</option>)}</select></label><label className="crm-outreach-field"><span>{ot("connection")}</span><select aria-label={ot("connection")} value={connectionValue} onChange={(event) => setConnectionValue(event.target.value)}>{OUTREACH_CONNECTION_STATES.map((state) => <option key={state} value={state}>{outreachConnectionLabel(state, lang)}</option>)}</select></label><label className="crm-outreach-field"><span>{ot("statusReason")}</span><input aria-label={ot("statusReason")} value={stageReason} onChange={(event) => setStageReason(event.target.value)} placeholder={ot("statusReasonHint")} /></label></div><div className="crm-outreach-inline-actions"><button type="button" className="crm-outreach-button" onClick={saveStatus} disabled={busy}>{ot("saveStatus")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={saveConnection} disabled={busy}>{lang === "de" ? "Vernetzung speichern" : "Save connection"}</button></div></section>
        <section className="crm-outreach-card" aria-label={lang === "de" ? "Verbindung angenommen" : "Connection accepted"}>
          <div className="crm-outreach-card-header"><h2>{lang === "de" ? "Verbindung angenommen" : "Connection accepted"}</h2><span>{lang === "de" ? "Manuell bestätigt" : "Manually confirmed"}</span></div>
          <p className="crm-outreach-muted">{lang === "de" ? "Nur nach echter LinkedIn-Prüfung. Das dokumentiert keinen versendeten Pitch." : "Only after checking LinkedIn. This does not record a sent pitch."}</p>
          <div className="crm-outreach-form-grid">
            <label className="crm-outreach-field"><span>{lang === "de" ? "Annahmetag" : "Acceptance day"}</span><input type="date" value={acceptanceDate} onChange={(event) => setAcceptanceDate(event.target.value)} /></label>
            <label className="crm-outreach-field"><span>{lang === "de" ? "HTTPS-Beleg-Link" : "HTTPS evidence link"}</span><input type="url" value={acceptanceEvidence} onChange={(event) => setAcceptanceEvidence(event.target.value)} placeholder="https://" /></label>
          </div>
          <label className="crm-outreach-field"><input type="checkbox" checked={acceptanceConfirmed} onChange={(event) => setAcceptanceConfirmed(event.target.checked)} /><span>{lang === "de" ? "Ich habe die Annahme für genau diesen Kontakt geprüft" : "I verified acceptance for this exact contact"}</span></label>
          <button type="button" className="crm-outreach-button" onClick={recordAcceptance} disabled={busy || !acceptanceConfirmed || !acceptanceDate || !acceptanceEvidence.trim()}>{lang === "de" ? "Annahme dokumentieren" : "Record acceptance"}</button>
        </section>
        <section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{ot("details")}</h2><span>{lang === "de" ? "Native CRM-Daten" : "Native CRM data"}</span></div><div className="crm-outreach-form-section"><h3>{lang === "de" ? "Kontakt" : "Contact"}</h3><div className="crm-outreach-form-grid">{[["first", "first"], ["last", "last"], ["title", "title"], ["email", "email"], ["phone", "phone"], ["linkedinUrl", "linkedinUrl"]].map(([key, label]) => <label className="crm-outreach-field" key={`contact-${key}`}><span>{ot(label)}</span><input aria-label={ot(label)} value={details.contact[key] || ""} onChange={(event) => updateDetails("contact", key, event.target.value)} /></label>)}</div></div><div className="crm-outreach-form-section"><h3>{lang === "de" ? "Firma" : "Company"}</h3><div className="crm-outreach-form-grid">{[["name", "companyName"], ["domain", "domain"], ["website", "website"], ["industry", "industry"], ["size", "size"], ["linkedinUrl", "linkedinUrl"]].map(([key, label]) => <label className="crm-outreach-field" key={`company-${key}`}><span>{ot(label)}</span><input aria-label={`${ot(label)} ${lang === "de" ? "Firma" : "Company"}`} value={details.company[key] || ""} onChange={(event) => updateDetails("company", key, event.target.value)} /></label>)}</div></div><div className="crm-outreach-form-section"><h3>Research</h3><div className="crm-outreach-form-grid">{[["position", "position"], ["employeeEstimate", "employeeEstimate"], ["estimatedRevenue", "estimatedRevenue"], ["industry", "industry"], ["website", "website"], ["linkedinUrl", "linkedinUrl"], ["domain", "domain"], ["research", "research"]].map(([key, label]) => <label className="crm-outreach-field" key={`research-${key}`}><span>{ot(label)}</span><input aria-label={`${ot(label)} Research`} value={details.research[key] || ""} onChange={(event) => updateDetails("research", key, event.target.value)} /></label>)}</div></div><button type="button" className="crm-outreach-button" onClick={saveDetails} disabled={busy}>{ot("saveDetails")}</button></section>
        <section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{ot("research")}</h2>{linkedinUrl && <button type="button" className="crm-outreach-link-button" onClick={openLinkedIn}>{ot("linkedin")}</button>}</div><div className="crm-outreach-research-grid"><div className="crm-outreach-research-item"><span>{lang === "de" ? "E-Mail" : "Email"}</span><p className="crm-outreach-research-value">{contact.email || ot("unknownEmail")}</p></div><div className="crm-outreach-research-item"><span>{lang === "de" ? "Domain" : "Domain"}</span><p className="crm-outreach-research-value">{company.domain || ot("unknownDomain")}</p></div>{researchRows.map(([label, value]) => <div className="crm-outreach-research-item" key={label}><span>{label}</span><p className="crm-outreach-research-value">{value}</p></div>)}{research.website && <div className="crm-outreach-research-item"><span>{lang === "de" ? "Website / Shop" : "Website / Shop"}</span>{researchWebsite ? <a className="crm-outreach-research-link" href={researchWebsite} target="_blank" rel="noreferrer">{research.website}</a> : <p className="crm-outreach-research-value">{research.website}</p>}</div>}</div></section>
      </div>
      <aside className="crm-outreach-detail-side"><section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{ot("activation")}</h2></div><label className="crm-outreach-field"><span>{ot("owner")}</span><select aria-label={ot("owner")} value={ownerId} onChange={(event) => setOwnerId(event.target.value)}><option value="">{ot("chooseOwner")}</option>{(data.owners || []).map((owner) => <option key={owner.id} value={owner.id}>{owner.name}</option>)}</select></label><label className="crm-outreach-field"><span>{ot("firstTask")}</span><input aria-label={ot("firstTask")} value={taskTitle} onChange={(event) => setTaskTitle(event.target.value)} placeholder={ot("nextStep")} /></label><label className="crm-outreach-field"><span>{ot("due")}</span><input aria-label={ot("due")} type="date" value={taskDueAt} onChange={(event) => setTaskDueAt(event.target.value)} /></label><button type="button" className="crm-outreach-button" onClick={activate} disabled={busy || member.executionState === "active"}>{ot("activate")}</button></section><section className="crm-outreach-card"><div className="crm-outreach-card-header"><h2>{lang === "de" ? "Datenverwaltung" : "Data management"}</h2><span>{lang === "de" ? "CRM-Export und Löschung" : "CRM export and deletion"}</span></div><div className="crm-outreach-inline-actions">{window.MesperDB?.crmExportCompany && <button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={exportCompanyData} disabled={busy}>{lang === "de" ? "CRM exportieren" : "Export CRM"}</button>}{window.MesperDB?.crmDeleteCompany && <button type="button" className="crm-outreach-button crm-outreach-button-danger" onClick={deleteCompanyData} disabled={busy}>{lang === "de" ? "Firma löschen" : "Delete company"}</button>}</div><p className="crm-outreach-muted">{lang === "de" ? "Die Löschung entfernt die verknüpften Outreach-Datensätze und hält den Import-Tombstone." : "Deletion removes linked outreach records and keeps the import tombstone."}</p></section><section className="crm-outreach-card"><h2>{ot("tasks")}</h2>{(data.tasks || []).map((task) => <div className="crm-outreach-task" key={task.id}><strong>{task.title}</strong><span>{task.dueAt ? formatOutreachDate(task.dueAt, lang) : ot("unknownDue")}</span></div>)}</section><section className="crm-outreach-card"><h2>{ot("timeline")}</h2>{(data.activities || []).map((activity) => <div className="crm-outreach-timeline" key={activity.id}><strong>{activity.type === "import" ? ot("import") : activity.type}</strong><span>{outreachTimelineLabel(activity, lang)}</span><p>{activity.body || ""}</p></div>)}</section></aside>
    </div>
    {sendOpen && <div className="crm-outreach-modal-backdrop" role="presentation"><div className="crm-outreach-modal" role="dialog" aria-modal="true" aria-label={ot("sendDialog")}><h2>{ot("sendDialog")}</h2>{configuredSequence && <p className="crm-outreach-muted">{lang === 'de' ? 'Nur bereits auf LinkedIn versendete Nachrichten bestätigen. Der nächste Schritt wird aus diesem Zeitpunkt automatisch geplant.' : 'Confirm only messages already sent on LinkedIn. The next step is scheduled automatically from this timestamp.'}</p>}<label className="crm-outreach-field"><span>{ot("sendType")}</span><select aria-label={ot("sendType")} value={sendType} onChange={(event) => setSendType(event.target.value)}><option value="pitch_sent">{ot("pitchSent")}</option><option value="followup_sent">{ot("followupSent")}</option></select></label><label className="crm-outreach-field"><span>{ot("actualTime")}</span><input aria-label={ot("actualTime")} type="datetime-local" value={sentAt} onChange={(event) => setSentAt(event.target.value)} /></label><div className="crm-outreach-modal-actions"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => setSendOpen(false)}>{ot("cancel")}</button><button type="button" className="crm-outreach-button" onClick={markSent} disabled={busy}>{ot("confirmSend")}</button></div></div></div>}
    {replyOpen && <div className="crm-outreach-modal-backdrop" role="presentation"><div className="crm-outreach-modal" role="dialog" aria-modal="true" aria-label={ot("replyDialog")}><h2>{ot("replyDialog")}</h2><label className="crm-outreach-field"><span>{ot("sentiment")}</span><select aria-label={ot("sentiment")} value={replySentiment} onChange={(event) => setReplySentiment(event.target.value)}><option value="positive">{ot("positive")}</option><option value="neutral">{ot("neutral")}</option><option value="negative">{ot("negative")}</option></select></label><label className="crm-outreach-field"><span>{lang === "de" ? "Antworttext" : "Reply text"}</span><textarea aria-label={lang === "de" ? "Antworttext" : "Reply text"} value={replyBody} onChange={(event) => setReplyBody(event.target.value)} rows="4" /></label><div className="crm-outreach-modal-actions"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => setReplyOpen(false)}>{ot("cancel")}</button><button type="button" className="crm-outreach-button" onClick={logReply} disabled={busy}>{ot("saveReply")}</button></div></div></div>}
  </section>;
}

function CrmOutreachList({ user, lang, navigate }) {
  const [filters, setFilters] = React.useState(readOutreachFilters);
  const [items, setItems] = React.useState([]);
  const [counts, setCounts] = React.useState(null);
  const [nextCursor, setNextCursor] = React.useState(null);
  const [ownerOptions, setOwnerOptions] = React.useState([]);
  const [campaignOptions, setCampaignOptions] = React.useState([]);
  const [campaignsReady, setCampaignsReady] = React.useState(false);
  const [loading, setLoading] = React.useState(true);
  const [loadingMore, setLoadingMore] = React.useState(false);
  const [error, setError] = React.useState(null);
  const requestKey = JSON.stringify(filters);

  React.useEffect(() => {
    let active = true;
    (async () => {
      try {
        if (!window.MesperOutreachDB?.campaigns) return;
        const campaigns = await window.MesperOutreachDB.campaigns();
        if (!active) return;
        const options = (campaigns || []).map((campaign) => ({
          id: campaign.id,
          name: campaign.name || campaign.id,
          channel: campaign.channel,
          enabled: Boolean(campaign.enabled),
          native: campaign.settings?.origin === "native_board" || campaign.name === "LinkedIn Outreach · Native Board",
        }));
        setCampaignOptions(options);
        setFilters((current) => {
          if (current.campaignId || !options.length) return current;
          const native = options.find((campaign) => campaign.native);
          return native ? { ...current, campaignId: native.id } : current;
        });
      } catch (_) {
        // The board remains usable if campaign metadata is unavailable.
      } finally {
        if (active) setCampaignsReady(true);
      }
    })();
    return () => { active = false; };
  }, []);

  React.useEffect(() => {
    let active = true;
    if (!campaignsReady) return () => { active = false; };
    setLoading(true);
    setError(null);
    saveOutreachFilters(filters);
    (async () => {
      try {
        if (!window.MesperOutreachDB) throw Object.assign(new Error("Outreach-Datenzugriff ist nicht konfiguriert"), { code: "NOT_CONFIGURED" });
        const result = await window.MesperOutreachDB.list(filters, { limit: 50, cursor: null });
        if (!active) return;
        const nextItems = result.items || [];
        setItems(nextItems);
        setCounts(result.counts || null);
        setNextCursor(result.nextCursor || null);
        const owners = result.owners || nextItems.reduce((all, item) => {
          if (item.ownerId && !all.some((owner) => owner.id === item.ownerId)) all.push({ id: item.ownerId, name: item.ownerName || item.ownerId });
          return all;
        }, []);
        setOwnerOptions(owners);
      } catch (loadError) {
        if (active) setError(loadError);
      } finally {
        if (active) setLoading(false);
      }
    })();
    return () => { active = false; };
  }, [requestKey, campaignsReady]);

  function updateFilter(key, value) {
    setFilters((previous) => ({ ...previous, [key]: value }));
  }

  async function loadMore() {
    if (!nextCursor || loadingMore) return;
    setLoadingMore(true);
    try {
      const result = await window.MesperOutreachDB.list(filters, { limit: 50, cursor: nextCursor });
      setItems((previous) => {
        const existing = new Set(previous.map((item) => item.memberId));
        return [...previous, ...(result.items || []).filter((item) => !existing.has(item.memberId))];
      });
      setCounts(result.counts || counts);
      setNextCursor(result.nextCursor || null);
    } catch (loadError) {
      setError(loadError);
    } finally {
      setLoadingMore(false);
    }
  }

  const retry = () => setFilters((previous) => ({ ...previous }));
  const applyFilter = (event) => updateFilter(event.target.name, event.target.type === "checkbox" ? event.target.checked : event.target.value);
  const resetFilters = () => setFilters({ search: "", ownerId: "", stage: "", connectionState: "", executionState: "", campaignId: "", dueOnly: false });

  const executionLabels = { draft: lang === "de" ? "Entwurf" : "Draft", active: lang === "de" ? "Aktiv" : "Active" };

  return <section className="crm-outreach-shell" aria-label={lang === "de" ? "LinkedIn Outreach" : "LinkedIn outreach"}>
    <div className="crm-outreach-header">
      <div>
        <h1 className="crm-outreach-title">LinkedIn Outreach</h1>
        <p className="crm-outreach-muted">{lang === "de" ? "Native CRM-Board für Research, manuelle Ansprache und Wiedervorlagen." : "Native CRM board for research, manual outreach and follow-ups."}</p>
      </div>
      <div className="crm-outreach-actions"><span className="crm-outreach-status-chip">{lang === "de" ? "Versand manuell" : "Manual sending"}</span><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={resetFilters}>{outreachDetailText(lang, "resetFilters")}</button><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => downloadOutreachCsv(items, lang)} disabled={!items.length}>{outreachDetailText(lang, "exportLoaded")}</button><button type="button" className="crm-outreach-button" onClick={() => navigate("/crm/outreach/new")}>{outreachDetailText(lang, "nativeCreate")}</button></div>
    </div>
    <div className="crm-outreach-actions crm-workflow-entry"><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={() => navigate('/crm/outreach/workflow')}>{lang === 'de' ? 'Workflow bearbeiten' : 'Edit workflow'}</button></div>
    <CrmOutreachPreferences user={user} lang={lang} />
    <div className="crm-outreach-filters" aria-label={lang === "de" ? "Filter" : "Filters"}>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Suche" : "Search"}</span><input name="search" value={filters.search} onChange={applyFilter} placeholder={lang === "de" ? "Brand oder Person" : "Brand or person"} /></label>
      <label className="crm-outreach-field"><span>Owner</span><select name="ownerId" value={filters.ownerId} onChange={applyFilter}><option value="">{lang === "de" ? "Alle Owner" : "All owners"}</option>{ownerOptions.map((owner) => <option key={owner.id} value={owner.id}>{owner.name}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Status" : "Stage"}</span><select name="stage" value={filters.stage} onChange={applyFilter}><option value="">{lang === "de" ? "Alle Status" : "All stages"}</option>{Object.keys(OUTREACH_STAGE_LABELS).map((stage) => <option key={stage} value={stage}>{outreachStageLabel(stage, lang)}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Vernetzung" : "Connection"}</span><select name="connectionState" value={filters.connectionState} onChange={applyFilter}><option value="">{lang === "de" ? "Alle Vernetzungen" : "All connections"}</option>{OUTREACH_CONNECTION_STATES.map((state) => <option key={state} value={state}>{outreachConnectionLabel(state, lang)}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Ausführung" : "Execution"}</span><select name="executionState" value={filters.executionState} onChange={applyFilter}><option value="">{lang === "de" ? "Alle Modi" : "All modes"}</option>{Object.entries(executionLabels).map(([state, label]) => <option key={state} value={state}>{label}</option>)}</select></label>
      <label className="crm-outreach-field"><span>{lang === "de" ? "Kampagne" : "Campaign"}</span><select name="campaignId" value={filters.campaignId} onChange={applyFilter}><option value="">{lang === "de" ? "Alle Kampagnen" : "All campaigns"}</option>{campaignOptions.map((campaign) => <option key={campaign.id} value={campaign.id}>{campaign.name}{campaign.native ? ` · ${lang === "de" ? "Board" : "Board"}` : ""}</option>)}</select></label>
      <label className="crm-outreach-checkbox"><input type="checkbox" name="dueOnly" checked={filters.dueOnly} onChange={applyFilter} /> {lang === "de" ? "Nur fällig" : "Due only"}</label>
    </div>
    {loading && <div className="crm-outreach-state" role="status">{lang === "de" ? "Lade Outreach…" : "Loading outreach…"}</div>}
    {!loading && error && <div className="crm-outreach-state crm-outreach-state-error" role="alert"><strong>{lang === "de" ? "Fehler beim Laden" : "Could not load outreach"}</strong><span>{error.message || (lang === "de" ? "Unbekannter Fehler" : "Unknown error")}</span><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={retry}>{lang === "de" ? "Erneut laden" : "Retry"}</button></div>}
    {!loading && !error && items.length === 0 && <div className="crm-outreach-state"><strong>{lang === "de" ? "Keine Kontakte gefunden" : "No contacts found"}</strong><span>{lang === "de" ? "Filter anpassen oder die Ausführung auf Alle Modi stellen." : "Adjust the filters or set execution to all modes."}</span></div>}
    {!loading && !error && items.length > 0 && <>
      <div className="crm-outreach-list-meta">{items.length}{nextCursor ? "+" : ""} {counts?.total != null && <span> {outreachDetailText(lang, "totalOf")} {counts.total}</span>} {lang === "de" ? "Kontakte" : "contacts"}</div>
      <div className="crm-outreach-list" role="list">
        {items.map((item) => <button type="button" role="listitem" className="crm-outreach-row" key={item.memberId} onClick={() => navigate(`/crm/outreach/m/${item.memberId}`)}>
          <span className="crm-outreach-row-main"><strong>{item.brandName || item.brand || "Unbekannte Brand"}</strong><span>{outreachContactLabel(item)}</span></span>
          <span className="crm-outreach-row-stage"><strong>{outreachStageLabel(item.stage, lang)}</strong><span>{outreachConnectionLabel(item.connectionState, lang)}</span></span>
          <span className="crm-outreach-row-touch"><strong>{formatOutreachDate(item.lastActivityAt, lang)}</strong><span>{item.nextTask?.title || (lang === "de" ? "Keine nächste Aktion" : "No next step")}</span></span>
          <span className="crm-outreach-row-owner">{item.ownerName || (lang === "de" ? "Owner fehlt" : "Owner missing")}</span>
        </button>)}
      </div>
      {nextCursor && <button type="button" className="crm-outreach-button crm-outreach-load-more" onClick={loadMore} disabled={loadingMore}>{loadingMore ? (lang === "de" ? "Lade…" : "Loading…") : (lang === "de" ? "Mehr laden" : "Load more")}</button>}
    </>}
  </section>;
}

function CrmOutreachImport({ user, lang, navigate }) {
  const [preview, setPreview] = React.useState(null);
  const [decisions, setDecisions] = React.useState({});
  const [loading, setLoading] = React.useState(true);
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState(null);
  const [notice, setNotice] = React.useState("");
  const isAdmin = user && ["admin", "ceo", "owner"].includes(String(user.role || "").toLowerCase());

  const loadPreview = React.useCallback(async () => {
    setLoading(true); setError(null); setNotice("");
    try {
      const result = await window.MesperOutreachDB.sheet("preview", { sourceId: "outreach-sheet" });
      setPreview(result);
      setDecisions({});
    } catch (loadError) { setError(loadError); }
    finally { setLoading(false); }
  }, []);
  React.useEffect(() => { loadPreview(); }, [loadPreview]);

  async function setupIds() {
    setBusy(true); setError(null);
    try { await window.MesperOutreachDB.sheet("setupIds", { sourceId: "outreach-sheet" }); setNotice(lang === "de" ? "IDs wurden vorbereitet." : "IDs prepared."); }
    catch (actionError) { setError(actionError); }
    finally { setBusy(false); }
  }

  async function applyImport() {
    setBusy(true); setError(null); setNotice("");
    try {
      const rows = (preview?.rows || []).map((row) => ({ sourceRecordId: row.sourceRecordId, decision: decisions[row.ordinal] || "skip" }));
      const result = await window.MesperOutreachDB.sheet("apply", { sourceId: "outreach-sheet", decisions: rows });
      setNotice(lang === "de" ? `Import abgeschlossen: ${result.counts?.created || 0} neu.` : `Import complete: ${result.counts?.created || 0} new.`);
    } catch (actionError) { setError(actionError); }
    finally { setBusy(false); }
  }

  const errorMessage = error?.code === "SOURCE_CHANGED" ? (lang === "de" ? "Das Sheet wurde seit der Vorschau geändert." : "The sheet changed since the preview.") : error?.code === "FORBIDDEN" ? (lang === "de" ? "Keine Berechtigung für diesen Import." : "You do not have permission to apply this import.") : error?.code === "NOT_CONFIGURED" ? (lang === "de" ? "Google Sheets ist nicht verbunden." : "Google Sheets is not connected.") : error?.message;

  return <section className="crm-outreach-shell crm-outreach-import" aria-label={lang === "de" ? "Importprüfung" : "Import review"}>
    <div className="crm-outreach-header"><div><button type="button" className="crm-outreach-back" onClick={() => navigate("/crm/outreach")}>← {lang === "de" ? "Outreach" : "Outreach"}</button><h1 className="crm-outreach-title">{lang === "de" ? "Importprüfung" : "Import review"}</h1></div><div className="crm-outreach-actions">{isAdmin && <><button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={setupIds} disabled={busy}>{lang === "de" ? "IDs ergänzen" : "Add IDs"}</button><button type="button" className="crm-outreach-button" onClick={applyImport} disabled={busy || loading || !preview}>{lang === "de" ? "Import anwenden" : "Apply import"}</button></>}</div></div>
    {loading && <div className="crm-outreach-state" role="status">{lang === "de" ? "Lade Vorschau…" : "Loading preview…"}</div>}
    {!loading && error && <div className="crm-outreach-state crm-outreach-state-error" role="alert"><strong>{errorMessage}</strong>{error.code === "SOURCE_CHANGED" && <button type="button" className="crm-outreach-button crm-outreach-button-secondary" onClick={loadPreview}>{lang === "de" ? "Vorschau erneuern" : "Refresh preview"}</button>}</div>}
    {!loading && !error && preview && <>
      <div className="crm-outreach-import-summary">{Object.entries(preview.counts || {}).map(([key, value]) => <div className="crm-outreach-summary-card" key={key}><strong>{value}</strong><span>{key}</span></div>)}<div className="crm-outreach-summary-sync"><span>{lang === "de" ? "Letzter erfolgreicher Sync" : "Last successful sync"}</span><strong>{formatOutreachDate(preview.lastSuccessfulSyncAt, lang)}</strong></div></div>
      {!isAdmin && <div className="crm-outreach-permission">{lang === "de" ? "Import anwenden ist nur für Admins verfügbar." : "Applying imports is available to admins only."}</div>}
      <div className="crm-outreach-import-rows">{(preview.rows || []).map((row) => <article className="crm-outreach-import-row" key={row.ordinal}><div><strong>{row.fullName || (lang === "de" ? "Unbekannte Person" : "Unknown person")}</strong><span>{row.brand || (lang === "de" ? "Unbekannte Brand" : "Unknown brand")}</span></div><span className="crm-outreach-issue-list">{(row.issueCodes || []).join(", ") || (lang === "de" ? "Keine Issues" : "No issues")}</span><label className="crm-outreach-field"><span>{lang === "de" ? "Entscheidung" : "Decision"}</span><select aria-label={`${lang === "de" ? "Entscheidung für" : "Decision for"} ${row.fullName || row.ordinal}`} value={decisions[row.ordinal] || "skip"} onChange={(event) => setDecisions((current) => ({ ...current, [row.ordinal]: event.target.value }))}><option value="skip">{lang === "de" ? "Überspringen" : "Skip"}</option><option value="link">{lang === "de" ? "Bestehende Person verknüpfen" : "Link existing person"}</option><option value="create">{lang === "de" ? "Neue Person/Firma bestätigen" : "Confirm new person/company"}</option><option value="accept_research">{lang === "de" ? "Research übernehmen" : "Accept research"}</option><option value="keep_crm">{lang === "de" ? "CRM behalten" : "Keep CRM"}</option></select></label>{row.status === "conflict" && <div className="crm-outreach-conflict"><span>{lang === "de" ? "Rohwert" : "Raw value"}: {row.raw?.Status || "-"}</span><span>{lang === "de" ? "CRM" : "CRM"}: {row.crmValue?.stage || "-"}</span></div>}</article>)}</div>
    </>}
    {notice && <div className="crm-outreach-notice" role="status">{notice}</div>}
  </section>;
}
