// admin-settings.jsx — Slack Notifications page.
// Everything WiseFunnel sends to Slack, in one place: connection, live
// channel routing, the REAL message template previews (kept in sync with the
// edge functions that send them), per-event "Send sample" (posts the actual
// template, [SAMPLE]-marked, to the mapped channel), and a read-only list of
// Slack senders that live outside this app (GitHub Actions / Cowork tasks).
const { useState: useStateS, useEffect: useEffectS } = React;
const Icon    = window.Icon;
const Btn     = window.Btn;
const Toggle  = window.Toggle;

const SUPABASE_URL  = 'https://iwvlmpgeodctctmaacja.supabase.co';
const REDIRECT_URI  = `${SUPABASE_URL}/functions/v1/slack-admin-oauth-callback`;

const CHANNEL_FIELDS = [
  { key: 'sales_channel_id',                label: '💰 Sales',         desc: 'New signups + paid subscriptions (aggregate)' },
  { key: 'signup_channel_id',               label: '🆕 Signups only',   desc: 'Free trial signups' },
  { key: 'subscription_paid_channel_id',    label: '💳 Paid subs only', desc: 'Paid subscription events' },
  { key: 'subscription_updated_channel_id', label: '📈 Plan changes',   desc: 'Upgrades, downgrades, renewals' },
  { key: 'watchdog_channel_id',             label: '🐶 Watchdog',       desc: 'Nightly lead-distribution health report' },
  { key: 'test_channel_id',                 label: '🧪 Test',           desc: 'Test notifications' },
];

// ─── The notification catalog ────────────────────────────────────────────────
// One entry per REAL Slack message this system sends. `preview` mirrors the
// exact template in the sending edge function — if you change a template
// there, update it here too (and vice versa).
const EVENT_CATALOG = [
  {
    id: 'signup',
    title: '🆕 New Free Trial Signup',
    sender: 'sales-slack-notification',
    trigger: 'Fires instantly when a new profile row is created (Postgres trigger on profiles INSERT) — catches every signup, with or without Stripe.',
    routes: ['signup_channel_id', 'sales_channel_id'],
    sample: 'signup',
    color: '#4A90E2',
    preview: [
      { type: 'header', text: '🆕 New Free Trial Signup' },
      { type: 'lines', lines: ['*Name:* Jane Doe', '*Email:* jane@example.com', '*Phone:* +1 555 010 1234'] },
      { type: 'lines', lines: ['*Plan Details*', '*Type:* Free Trial', '*Plan:* Trial'] },
      { type: 'lines', lines: ['*Stripe Account Status*', '✅ Stripe account created successfully (cus_…)'] },
      { type: 'buttons', buttons: ['✉️ Contact by Email'] },
    ],
  },
  {
    id: 'subscription_paid',
    title: '💰 New Paid Subscription',
    sender: 'sales-slack-notification',
    trigger: 'Fires when Stripe confirms payment (checkout.session.completed webhook).',
    routes: ['subscription_paid_channel_id', 'sales_channel_id'],
    sample: 'subscription_paid',
    color: '#FFD700',
    preview: [
      { type: 'header', text: '💰 New Paid Subscription' },
      { type: 'lines', lines: ['*Name:* Jane Doe', '*Email:* jane@example.com', '*Phone:* +1 555 010 1234'] },
      { type: 'lines', lines: ['*Plan Details*', '*Type:* Paid Subscription', '*Plan:* Growth', '*Amount:* $97.00', '*Date:* Jun 6, 2026, 2:00 PM UTC'] },
      { type: 'lines', lines: ['*Stripe Account Status*', '✅ Stripe account created successfully (cus_…)'] },
      { type: 'buttons', buttons: ['✉️ Contact by Email'] },
    ],
  },
  {
    id: 'subscription_updated',
    title: '🔄 Plan Change',
    sender: 'admin-notifications',
    trigger: 'Fires on Stripe customer.subscription.updated (upgrades, downgrades, renewals).',
    routes: ['subscription_updated_channel_id'],
    sample: 'subscription_updated',
    color: '#36a64f',
    preview: [
      { type: 'lines', lines: ['🔄 *Subscription Updated*'] },
      { type: 'lines', lines: ['👤 *User:* jane@example.com', '📦 *New Plan:* Scale', '📅 *Date:* Jun 6, 2026, 2:00 PM (UTC)'] },
    ],
  },
  {
    id: 'watchdog',
    title: '🐶 Lead Distribution Watchdog',
    sender: 'distribution-watchdog',
    trigger: 'Nightly at 01:15 UTC (9:15 PM EST), right after the daily cap reset. Reconciles buyer counters vs delivery history, flags silent failures, checks the retry queue.',
    routes: ['watchdog_channel_id'],
    sample: 'watchdog',
    color: '#F97316',
    preview: [
      { type: 'lines', lines: ['🐶 *Lead Distribution Watchdog · Fri, Jun 6*'] },
      { type: 'lines', lines: ['✅ All checks passed — counters match delivery history, every recent lead has a recorded outcome, cap resets ran, retry queue healthy.'] },
    ],
  },
  {
    id: 'test',
    title: '✅ Test Notification',
    sender: 'admin-settings',
    trigger: 'On demand — the "Send Test" button below.',
    routes: ['test_channel_id'],
    sample: null, // uses the dedicated Send Test action
    color: '#9333EA',
    preview: [
      { type: 'lines', lines: ['✅ *Test Notification*'] },
      { type: 'lines', lines: ['Hello from WiseFunnel Admin 👋', 'If you see this, internal Slack notifications are wired up correctly.'] },
    ],
  },
];

// Slack senders that are configured OUTSIDE this page (GitHub Actions /
// Cowork scheduled tasks / per-workspace user integrations). Shown read-only
// so this page is the single source of truth for "what posts to Slack".
const EXTERNAL_SENDERS = [
  { icon: '📊', name: 'Daily User Summary',        where: 'GitHub Actions · daily 11:05 PM ET', channel: '#sales', note: 'Active subscriber roll-call with plans, LTV, funnels. Replaced the old 11 PM UTC pg_cron version (now unscheduled — it was double-posting).' },
  { icon: '🗂️', name: 'Daily PM Briefing',          where: 'GitHub Actions · daily 5 AM ET',     channel: '#project-management', note: 'Trello board state, Inbox grooming, build queue.' },
  { icon: '✍️', name: 'Prompt Writer',              where: 'Cowork task · daily ~9 AM ET',       channel: '#project-management', note: 'Writes 🤖 Build Prompts for cards that need them.' },
  { icon: '🧪', name: 'Lead-Routing Health Check',  where: 'Cowork task · daily ~6 AM ET',       channel: '#lead-routing-test', note: 'Live funnel walkthrough + full pipeline verification.' },
  { icon: '⚡', name: 'Weekly Funnel Speed Audit',  where: 'GitHub Actions · Mondays 5 AM ET',   channel: '#funnel-performance', note: 'PageSpeed benchmark vs competitors.' },
];

function ChannelSelect({ channels, value, onChange, placeholder }) {
  return (
    <select
      value={value || ''}
      onChange={e => onChange(e.target.value || null)}
      style={{
        width: '100%', padding: '7px 10px', borderRadius: 8,
        border: '1px solid #E5E7EB', fontFamily: 'inherit', fontSize: 13,
        color: value ? '#1A2B3B' : '#9CA3AF', background: '#fff',
        cursor: 'pointer', outline: 'none',
      }}
    >
      <option value="">{placeholder || '— not set —'}</option>
      {channels.map(ch => (
        <option key={ch.id} value={ch.id}>#{ch.name}{ch.is_private ? ' 🔒' : ''}</option>
      ))}
    </select>
  );
}

function StatusBadge({ connected }) {
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5, padding: '3px 10px',
      borderRadius: 999, fontSize: 11, fontWeight: 700,
      background: connected ? '#D1FAE5' : '#F3F4F6',
      color: connected ? '#065F46' : '#6B7280',
    }}>
      <span style={{ width: 6, height: 6, borderRadius: '50%', background: connected ? '#10B981' : '#9CA3AF', display: 'inline-block' }}/>
      {connected ? 'Connected' : 'Not connected'}
    </span>
  );
}

function Card({ children, style }) {
  return (
    <div style={{ background: '#fff', border: '1px solid #E5E7EB', borderRadius: 14, padding: 24, ...style }}>
      {children}
    </div>
  );
}

// Minimal Slack-mrkdwn → HTML: *bold* only (matches what the templates use).
function mrkdwn(text) {
  const esc = String(text).replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  return esc.replace(/\*([^*]+)\*/g, '<strong>$1</strong>');
}

// Slack-style message preview (white card, colored attachment bar).
function SlackPreview({ blocks, color }) {
  return (
    <div style={{ background: '#FFFFFF', border: '1px solid #E5E7EB', borderRadius: 10, padding: '10px 12px', display: 'flex', gap: 10 }}>
      <div style={{ width: 4, borderRadius: 4, background: color || '#E5E7EB', flexShrink: 0 }} />
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, minWidth: 0, paddingTop: 2 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
          <div style={{ width: 18, height: 18, borderRadius: 4, background: '#F97316', color: '#fff', fontSize: 10, fontWeight: 900, display: 'flex', alignItems: 'center', justifyContent: 'center' }}>W</div>
          <span style={{ fontSize: 12, fontWeight: 800, color: '#1A2B3B' }}>WiseFunnel</span>
          <span style={{ fontSize: 10, color: '#9CA3AF', background: '#F3F4F6', borderRadius: 3, padding: '0 4px', fontWeight: 700 }}>APP</span>
        </div>
        {blocks.map((b, i) => {
          if (b.type === 'header') {
            return <div key={i} style={{ fontSize: 14, fontWeight: 900, color: '#1A2B3B' }}>{b.text}</div>;
          }
          if (b.type === 'buttons') {
            return (
              <div key={i} style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                {b.buttons.map((label, j) => (
                  <span key={j} style={{ fontSize: 11, fontWeight: 700, color: j === 0 ? '#fff' : '#1A2B3B', background: j === 0 ? '#007A5A' : '#fff', border: '1px solid #D1D5DB', borderRadius: 6, padding: '4px 10px' }}>{label}</span>
                ))}
              </div>
            );
          }
          return (
            <div key={i} style={{ fontSize: 12, color: '#374151', lineHeight: 1.55 }}>
              {b.lines.map((ln, j) => (
                <div key={j} dangerouslySetInnerHTML={{ __html: mrkdwn(ln) }} />
              ))}
            </div>
          );
        })}
      </div>
    </div>
  );
}

function SettingsPage() {
  const [loading, setLoading]         = useStateS(true);
  const [saving, setSaving]           = useStateS(false);
  const [testing, setTesting]         = useStateS(false);
  const [disconnecting, setDisconn]   = useStateS(false);
  const [connected, setConnected]     = useStateS(false);
  const [teamName, setTeamName]       = useStateS(null);
  const [installedBy, setInstalledBy] = useStateS(null);
  const [channels, setChannels]       = useStateS([]);
  const [mappings, setMappings]       = useStateS({});
  const [toast, setToast]             = useStateS(null);
  const [testChannel, setTestChannel] = useStateS('');
  const [urlStatus, setUrlStatus]     = useStateS(null); // 'connected' | 'error'
  const [slackClientId, setSlackClientId] = useStateS(null);
  const [sampling, setSampling]       = useStateS(null);  // event id being sampled
  const [openPreview, setOpenPreview] = useStateS('signup');

  const adminEmail = window.AdminAuth?.get()?.email || window.MOCK?.admin?.email || '';

  const showToast = (msg, type = 'success') => {
    setToast({ msg, type });
    setTimeout(() => setToast(null), 3500);
  };

  // Handle OAuth redirect result (?slack=connected or ?slack=error)
  useEffectS(() => {
    const params = new URLSearchParams(location.search);
    const slack = params.get('slack');
    if (slack === 'connected') {
      setUrlStatus('connected');
      showToast('Slack connected successfully!', 'success');
    } else if (slack === 'error') {
      const errCode = params.get('slack_error') || 'unknown_error';
      setUrlStatus('error');
      showToast(`Slack connection failed: ${errCode}`, 'error');
    }
    if (slack) {
      const clean = new URL(location.href);
      clean.searchParams.delete('slack');
      clean.searchParams.delete('slack_error');
      clean.searchParams.delete('section');
      history.replaceState({}, '', clean.toString());
    }
  }, []);

  const loadStatus = async () => {
    setLoading(true);
    try {
      const res = await fetch(`${SUPABASE_URL}/functions/v1/admin-settings`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'get_slack_status', admin_email: adminEmail }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Failed to load');

      setConnected(!!data.connected);
      setTeamName(data.team_name || null);
      setInstalledBy(data.installed_by || null);
      setChannels(data.channels || []);
      setMappings(data.channel_mappings || {});
      if (data.channels_error) showToast(`Slack token may be expired: ${data.channels_error}`, 'error');
    } catch (e) {
      showToast(`Error loading Slack status: ${e.message}`, 'error');
    } finally {
      setLoading(false);
    }
  };

  // Fetch public OAuth config (client IDs) on mount
  useEffectS(() => {
    fetch(`${SUPABASE_URL}/functions/v1/oauth-config`)
      .then(r => r.json())
      .then(d => { if (d.slack_admin_client_id) setSlackClientId(d.slack_admin_client_id); })
      .catch(() => {}); // non-fatal
  }, []);

  useEffectS(() => { if (adminEmail) loadStatus(); }, [adminEmail]);

  const channelName = (id) => {
    if (!id) return null;
    const ch = channels.find(c => c.id === id);
    return ch ? `#${ch.name}` : id;
  };

  const connectSlack = () => {
    if (!adminEmail) { showToast('No admin session found', 'error'); return; }
    if (!slackClientId) { showToast('Slack client ID not loaded yet — please retry in a moment', 'error'); return; }
    const state = encodeURIComponent(JSON.stringify({ adminEmail, returnTo: 'https://admin.wisefunnel.io' }));
    const scopes = 'chat:write,channels:read,groups:read,channels:join';
    const url = `https://slack.com/oauth/v2/authorize?client_id=${slackClientId}&scope=${scopes}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}&state=${state}`;
    location.href = url;
  };

  const saveChannels = async () => {
    setSaving(true);
    try {
      const res = await fetch(`${SUPABASE_URL}/functions/v1/admin-settings`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'set_slack_channels', admin_email: adminEmail, channel_mappings: mappings }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Failed to save');
      showToast('Channel settings saved!');
    } catch (e) {
      showToast(`Save failed: ${e.message}`, 'error');
    } finally {
      setSaving(false);
    }
  };

  const sendTest = async () => {
    setTesting(true);
    try {
      const res = await fetch(`${SUPABASE_URL}/functions/v1/admin-settings`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'send_slack_test', admin_email: adminEmail, channel_id: testChannel || mappings.test_channel_id || mappings.sales_channel_id }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Test failed');
      showToast('Test message sent! Check Slack 👋');
    } catch (e) {
      showToast(`Test failed: ${e.message}`, 'error');
    } finally {
      setTesting(false);
    }
  };

  const sendSample = async (eventType) => {
    setSampling(eventType);
    try {
      const res = await fetch(`${SUPABASE_URL}/functions/v1/admin-settings`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'send_slack_sample', admin_email: adminEmail, event_type: eventType }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Sample failed');
      const sent = (data.results || []).filter(r => r.ok).map(r => channelName(r.channel) || r.channel).join(', ');
      showToast(`Sample sent to ${sent || 'Slack'} ✓`);
    } catch (e) {
      showToast(`Sample failed: ${e.message}`, 'error');
    } finally {
      setSampling(null);
    }
  };

  const disconnect = async () => {
    if (!confirm('Disconnect Slack? Notifications will stop immediately.')) return;
    setDisconn(true);
    try {
      const res = await fetch(`${SUPABASE_URL}/functions/v1/admin-settings`, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ action: 'disconnect_slack', admin_email: adminEmail }),
      });
      const data = await res.json();
      if (!res.ok) throw new Error(data.error || 'Disconnect failed');
      setConnected(false);
      setTeamName(null);
      setChannels([]);
      setMappings({});
      showToast('Slack disconnected.');
    } catch (e) {
      showToast(`Disconnect failed: ${e.message}`, 'error');
    } finally {
      setDisconn(false);
    }
  };

  const SlackLogo = ({ size = 24 }) => (
    <svg width={size} height={size} viewBox="0 0 24 24" fill="none" style={{ flexShrink: 0 }}>
      <path d="M5.042 15.165a2.528 2.528 0 0 1-2.52 2.523A2.528 2.528 0 0 1 0 15.165a2.527 2.527 0 0 1 2.522-2.52h2.52v2.52zM6.313 15.165a2.527 2.527 0 0 1 2.521-2.52 2.527 2.527 0 0 1 2.521 2.52v6.313A2.528 2.528 0 0 1 8.834 24a2.528 2.528 0 0 1-2.521-2.522v-6.313z" fill="#E01E5A"/>
      <path d="M8.834 5.042a2.528 2.528 0 0 1-2.521-2.52A2.528 2.528 0 0 1 8.834 0a2.528 2.528 0 0 1 2.521 2.522v2.52H8.834zM8.834 6.313a2.528 2.528 0 0 1 2.521 2.521 2.528 2.528 0 0 1-2.521 2.521H2.522A2.528 2.528 0 0 1 0 8.834a2.528 2.528 0 0 1 2.522-2.521h6.312z" fill="#36C5F0"/>
      <path d="M18.956 8.834a2.528 2.528 0 0 1 2.522-2.521A2.528 2.528 0 0 1 24 8.834a2.528 2.528 0 0 1-2.522 2.521h-2.522V8.834zM17.688 8.834a2.528 2.528 0 0 1-2.523 2.521 2.527 2.527 0 0 1-2.52-2.521V2.522A2.527 2.527 0 0 1 15.165 0a2.528 2.528 0 0 1 2.523 2.522v6.312z" fill="#2EB67D"/>
      <path d="M15.165 18.956a2.528 2.528 0 0 1 2.523 2.522A2.528 2.528 0 0 1 15.165 24a2.527 2.527 0 0 1-2.52-2.522v-2.522h2.52zM15.165 17.688a2.527 2.527 0 0 1-2.52-2.523 2.526 2.526 0 0 1 2.52-2.52h6.313A2.527 2.527 0 0 1 24 15.165a2.528 2.528 0 0 1-2.522 2.523h-6.313z" fill="#ECB22E"/>
    </svg>
  );

  return (
    <div style={{ maxWidth: 760, display: 'flex', flexDirection: 'column', gap: 20 }}>

      {/* Toast */}
      {toast && (
        <div style={{
          position: 'fixed', top: 20, right: 20, zIndex: 999,
          padding: '10px 18px', borderRadius: 10, fontSize: 13, fontWeight: 600,
          background: toast.type === 'error' ? '#FEE2E2' : '#D1FAE5',
          color: toast.type === 'error' ? '#991B1B' : '#065F46',
          boxShadow: '0 4px 16px rgba(0,0,0,0.12)',
          animation: 'fadeUp 0.2s ease-out',
        }}>
          {toast.msg}
        </div>
      )}

      {/* Header */}
      <div>
        <h2 style={{ fontSize: 18, fontWeight: 800, color: '#1A2B3B', marginBottom: 4 }}>Slack Notifications</h2>
        <p style={{ fontSize: 13, color: '#6B7280' }}>Everything WiseFunnel sends to Slack — connection, live channel routing, and the exact messages.</p>
      </div>

      {/* ── 1. Connection + Channel Routing ── */}
      <Card>
        <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 16, marginBottom: 20 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{ width: 42, height: 42, borderRadius: 10, background: '#fff', border: '1px solid #E5E7EB', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <SlackLogo />
            </div>
            <div>
              <div style={{ fontSize: 14, fontWeight: 800, color: '#1A2B3B' }}>Slack</div>
              <div style={{ fontSize: 12, color: '#6B7280', marginTop: 2 }}>Internal notifications for the WiseFunnel team</div>
            </div>
          </div>
          <StatusBadge connected={connected} />
        </div>

        {loading ? (
          <div style={{ display: 'flex', alignItems: 'center', gap: 8, color: '#9CA3AF', fontSize: 13 }}>
            <Icon name="Loader" size={14} color="#9CA3AF" /> Loading…
          </div>
        ) : !connected ? (
          /* ── Disconnected state ── */
          <div>
            <p style={{ fontSize: 13, color: '#6B7280', marginBottom: 16, lineHeight: 1.6 }}>
              Connect your Slack workspace to receive real-time notifications for new signups,
              paid subscriptions, plan changes, and the nightly lead-distribution watchdog.
            </p>
            <Btn variant="primary" onClick={connectSlack}>
              <SlackLogo size={14} />
              Connect Slack Workspace
            </Btn>
          </div>
        ) : (
          /* ── Connected state ── */
          <div style={{ display: 'flex', flexDirection: 'column', gap: 20 }}>

            <div style={{ background: '#F0FDF4', border: '1px solid #A7F3D0', borderRadius: 10, padding: '12px 16px', display: 'flex', alignItems: 'center', gap: 10 }}>
              <Icon name="CheckCircle" size={16} color="#10B981" />
              <div style={{ fontSize: 13, color: '#065F46' }}>
                Connected to <strong>{teamName || 'your workspace'}</strong>
                {installedBy && <span style={{ color: '#6B7280', fontWeight: 400 }}> · installed by {installedBy}</span>}
              </div>
            </div>

            {/* Channel mappings */}
            <div>
              <div style={{ fontSize: 13, fontWeight: 700, color: '#1A2B3B', marginBottom: 14 }}>Channel Routing</div>
              <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
                {CHANNEL_FIELDS.map(f => (
                  <div key={f.key} style={{ display: 'grid', gridTemplateColumns: '210px 1fr', alignItems: 'center', gap: 12 }}>
                    <div>
                      <div style={{ fontSize: 13, fontWeight: 600, color: '#1A2B3B' }}>{f.label}</div>
                      <div style={{ fontSize: 11, color: '#9CA3AF', marginTop: 1 }}>{f.desc}</div>
                    </div>
                    <ChannelSelect
                      channels={channels}
                      value={mappings[f.key]}
                      onChange={val => setMappings(m => ({ ...m, [f.key]: val }))}
                    />
                  </div>
                ))}
              </div>
              <div style={{ marginTop: 6, fontSize: 11, color: '#9CA3AF', lineHeight: 1.5 }}>
                💡 Signups + paid events post to BOTH their own channel and <strong>Sales</strong> (when both are set). Same channel twice = posted once.
              </div>
            </div>

            {/* Actions row */}
            <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap', paddingTop: 4, borderTop: '1px solid #F3F4F6' }}>
              <Btn variant="primary" onClick={saveChannels} disabled={saving}>
                {saving ? <><Icon name="Loader" size={12} color="#fff"/>Saving…</> : <><Icon name="Save" size={12} color="#fff"/>Save Channels</>}
              </Btn>
              <Btn variant="secondary" onClick={sendTest} disabled={testing}>
                {testing ? <><Icon name="Loader" size={12} color="#1A2B3B"/>Sending…</> : <><Icon name="Send" size={12} color="#6B7280"/>Send Test</>}
              </Btn>
              <div style={{ flex: 1 }} />
              <Btn variant="danger" onClick={disconnect} disabled={disconnecting}>
                {disconnecting ? 'Disconnecting…' : <><Icon name="Power" size={12} color="#F43F5E"/>Disconnect</>}
              </Btn>
            </div>
          </div>
        )}
      </Card>

      {/* ── 2. What gets sent (real templates) ── */}
      {connected && !loading && (
        <Card>
          <div style={{ marginBottom: 4 }}>
            <div style={{ fontSize: 14, fontWeight: 800, color: '#1A2B3B' }}>What gets sent</div>
            <div style={{ fontSize: 12, color: '#6B7280', marginTop: 2 }}>
              The exact messages production sends, with their triggers and live destinations. "Send sample" posts the real template (marked SAMPLE) to the mapped channel.
            </div>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column' }}>
            {EVENT_CATALOG.map((ev, idx) => {
              const dests = [...new Set(ev.routes.map(r => mappings[r]).filter(Boolean))];
              const destLabels = dests.map(channelName);
              const isOpen = openPreview === ev.id;
              return (
                <div key={ev.id} style={{ padding: '14px 0', borderTop: idx === 0 ? 'none' : '1px solid #F3F4F6' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 10, flexWrap: 'wrap' }}>
                    <button
                      onClick={() => setOpenPreview(isOpen ? null : ev.id)}
                      style={{ background: 'none', border: 'none', padding: 0, cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8, fontFamily: 'inherit' }}
                    >
                      <span style={{ fontSize: 11, color: '#9CA3AF', transform: isOpen ? 'rotate(90deg)' : 'none', transition: 'transform .15s', display: 'inline-block' }}>▶</span>
                      <span style={{ fontSize: 13, fontWeight: 800, color: '#1A2B3B' }}>{ev.title}</span>
                    </button>
                    <div style={{ flex: 1 }} />
                    {destLabels.length > 0 ? destLabels.map((d, i) => (
                      <span key={i} style={{ fontSize: 11, fontWeight: 700, color: '#9A3412', background: '#FFF7ED', border: '1px solid #FED7AA', borderRadius: 999, padding: '2px 9px' }}>{d}</span>
                    )) : (
                      <span style={{ fontSize: 11, fontWeight: 700, color: '#991B1B', background: '#FEF2F2', border: '1px solid #FECACA', borderRadius: 999, padding: '2px 9px' }}>no channel — silent</span>
                    )}
                    {ev.sample && (
                      <Btn variant="secondary" onClick={() => sendSample(ev.sample)} disabled={sampling === ev.sample || dests.length === 0}>
                        {sampling === ev.sample ? <><Icon name="Loader" size={11} color="#1A2B3B"/>Sending…</> : <><Icon name="Send" size={11} color="#6B7280"/>Send sample</>}
                      </Btn>
                    )}
                  </div>
                  <div style={{ fontSize: 11, color: '#6B7280', margin: '6px 0 0 19px', lineHeight: 1.5 }}>
                    {ev.trigger} <span style={{ color: '#C4C9D0' }}>· {ev.sender}</span>
                  </div>
                  {isOpen && (
                    <div style={{ margin: '10px 0 2px 19px', maxWidth: 520 }}>
                      <SlackPreview blocks={ev.preview} color={ev.color} />
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        </Card>
      )}

      {/* ── 3. Sent from outside this page (read-only) ── */}
      <Card>
        <div style={{ fontSize: 14, fontWeight: 800, color: '#1A2B3B' }}>Also posting to Slack (managed elsewhere)</div>
        <div style={{ fontSize: 12, color: '#6B7280', marginTop: 2, marginBottom: 14 }}>
          These run in GitHub Actions or Cowork scheduled tasks — listed here so nothing is invisible. Change them in their own workflow/task.
        </div>
        <div style={{ display: 'flex', flexDirection: 'column', gap: 0 }}>
          {EXTERNAL_SENDERS.map((s, i) => (
            <div key={i} style={{ display: 'flex', alignItems: 'flex-start', gap: 10, padding: '10px 0', borderTop: i === 0 ? 'none' : '1px solid #F3F4F6' }}>
              <span style={{ fontSize: 16, lineHeight: '20px' }}>{s.icon}</span>
              <div style={{ minWidth: 0, flex: 1 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8, flexWrap: 'wrap' }}>
                  <span style={{ fontSize: 13, fontWeight: 700, color: '#1A2B3B' }}>{s.name}</span>
                  <span style={{ fontSize: 11, fontWeight: 700, color: '#3730A3', background: '#EEF2FF', border: '1px solid #C7D2FE', borderRadius: 999, padding: '2px 9px' }}>{s.channel}</span>
                  <span style={{ fontSize: 11, color: '#9CA3AF' }}>{s.where}</span>
                </div>
                <div style={{ fontSize: 11, color: '#6B7280', marginTop: 2, lineHeight: 1.5 }}>{s.note}</div>
              </div>
            </div>
          ))}
        </div>
        <div style={{ marginTop: 14, padding: '10px 14px', background: '#F8FAFC', border: '1px solid #E2E8F0', borderRadius: 10, fontSize: 11, color: '#64748B', lineHeight: 1.6 }}>
          ℹ️ <strong>Customer notifications are separate:</strong> lead delivered / delivery failed / daily distribution report / weekly funnel digest go to each customer workspace's OWN Slack connection (main app → Integrations → Slack). The destination channel is whatever that user picked during Slack authorization — it's not controlled from this page.
        </div>
      </Card>

    </div>
  );
}

Object.assign(window, { SettingsPage });
