/* account.jsx — persistent profile (localStorage) + Settings UI */

const STORAGE_KEY = 'aiso:profile:v1';

function loadProfile() {
  try {
    const raw = localStorage.getItem(STORAGE_KEY);
    if (!raw) return null;
    return migrateProfile(JSON.parse(raw));
  } catch {
    return null;
  }
}

function saveProfile(p) {
  try {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(p));
  } catch {}
}

function migrateProfile(p) {
  if (!p) return null;
  // legacy single-brand → multi-site
  if (p.brand && !p.sites) {
    const id = 's-' + Date.now();
    const { brand, ...rest } = p;
    return { ...rest, sites: [{ id, ...brand }], activeSiteId: id };
  }
  if (!p.sites) p.sites = [];
  if (!p.activeSiteId && p.sites[0]) p.activeSiteId = p.sites[0].id;
  return p;
}

function makeSite(partial = {}) {
  return {
    id: 's-' + Math.random().toString(36).slice(2, 9),
    name: '',
    domain: '',
    industry: '',
    location: '',
    competitors: [],
    addedAt: Date.now(),
    ...partial,
  };
}

function defaultProfile() {
  const first = makeSite({
    name: 'Bekon AI',
    domain: 'bekon.ai',
    industry: 'AI visibility platform',
    location: 'Online',
    competitors: ['Profound', 'Peec AI', 'Otterly.AI'],
  });
  return {
    email: '',
    name: '',
    sites: [first],
    activeSiteId: first.id,
    keys: {
      openai: '',
      anthropic: '',
      google: '',
      perplexity: '',
      xai: '',
      deepseek: '',
    },
    notifications: { email: true, slack: false, push: true, sms: false, threshold: 5 },
    plan: 'Free',
    createdAt: Date.now(),
    lastSignedIn: Date.now(),
  };
}

function getActiveSite(profile) {
  return (profile.sites || []).find((s) => s.id === profile.activeSiteId) || (profile.sites || [])[0] || null;
}

function useProfile() {
  const [profile, setProfile] = React.useState(() => loadProfile() || defaultProfile());

  function update(patch) {
    setProfile((prev) => {
      const next = typeof patch === 'function' ? patch(prev) : { ...prev, ...patch };
      saveProfile(next);
      return next;
    });
  }
  function updateActiveSite(patch) {
    update((prev) => ({
      ...prev,
      sites: (prev.sites || []).map((s) => s.id === prev.activeSiteId ? { ...s, ...patch } : s),
    }));
  }
  function updateSiteById(siteId, patch) {
    update((prev) => ({
      ...prev,
      sites: (prev.sites || []).map((s) => s.id === siteId ? { ...s, ...patch } : s),
    }));
  }
  function addSite(partial = {}) {
    const site = makeSite(partial);
    update((prev) => ({
      ...prev,
      sites: [...(prev.sites || []), site],
      activeSiteId: site.id,
    }));
    return site;
  }
  function removeSite(siteId) {
    update((prev) => {
      const sites = (prev.sites || []).filter((s) => s.id !== siteId);
      const activeSiteId = prev.activeSiteId === siteId ? (sites[0]?.id || null) : prev.activeSiteId;
      return { ...prev, sites, activeSiteId };
    });
  }
  function setActiveSite(siteId) {
    update({ activeSiteId: siteId });
  }
  function setKey(provider, key) {
    update((prev) => ({ ...prev, keys: { ...prev.keys, [provider]: key } }));
  }
  function updateNotifications(patch) {
    update((prev) => ({ ...prev, notifications: { ...prev.notifications, ...patch } }));
  }
  function saveSiteScan(siteId, scanResult) {
    update((prev) => ({
      ...prev,
      sites: (prev.sites || []).map((s) => s.id === siteId ? { ...s, lastScan: scanResult } : s),
    }));
  }
  function signOut() {
    try { localStorage.removeItem(STORAGE_KEY); } catch {}
    setProfile(defaultProfile());
  }
  function signIn(email, name) {
    update({ email, name: name || email.split('@')[0], lastSignedIn: Date.now() });
  }

  return {
    profile,
    activeSite: getActiveSite(profile),
    update,
    updateActiveSite,
    updateSiteById,
    addSite,
    removeSite,
    setActiveSite,
    setKey,
    updateNotifications,
    saveSiteScan,
    signOut,
    signIn,
  };
}

function initials(s) {
  if (!s) return '·';
  const parts = String(s).trim().split(/[\s@.]+/).filter(Boolean);
  if (parts.length === 0) return '·';
  if (parts.length === 1) return parts[0].slice(0, 2).toUpperCase();
  return (parts[0][0] + parts[1][0]).toUpperCase();
}

/* ---------- icons ---------- */
function Eye() { return <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1.5 7s2-4 5.5-4 5.5 4 5.5 4-2 4-5.5 4S1.5 7 1.5 7z" stroke="currentColor" strokeWidth="1.4"/><circle cx="7" cy="7" r="1.6" stroke="currentColor" strokeWidth="1.4"/></svg>; }
function EyeOff() { return <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M1.5 7s2-4 5.5-4c1.2 0 2.3.4 3.2 1M12.5 7s-2 4-5.5 4c-1.2 0-2.3-.4-3.2-1M2 2l10 10" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round"/></svg>; }
function Cog() { return <svg width="16" height="16" viewBox="0 0 16 16" fill="none"><path d="M8 5.5a2.5 2.5 0 1 0 0 5 2.5 2.5 0 0 0 0-5z" stroke="currentColor" strokeWidth="1.3"/><path d="M8 1.5l.7 1.5 1.6.2.3 1.6 1.4.9-.3 1.6 1 1.2-1 1.2.3 1.6-1.4.9-.3 1.6-1.6.2L8 14.5l-.7-1.5-1.6-.2-.3-1.6-1.4-.9.3-1.6-1-1.2 1-1.2-.3-1.6 1.4-.9.3-1.6 1.6-.2L8 1.5z" stroke="currentColor" strokeWidth="1.1" strokeLinejoin="round"/></svg>; }

/* ---------- Settings ---------- */
function Settings({ profile, activeSite, update, updateActiveSite, updateSiteById, addSite, onAddAndScan, removeSite, setActiveSite, updateNotifications, signOut, onBack, initialTab = 'sites' }) {
  const [tab, setTab] = React.useState(initialTab === 'keys' ? 'integrations' : initialTab);

  return (
    <section className="container fade-in settings-scene">
      <div className="settings-head">
        <button className="crumb-btn" onClick={onBack}>
          <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M9 3l-4 4 4 4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>
          Back
        </button>
        <h1>Settings</h1>
        <div className="settings-id">
          <div className="avatar">{initials(profile.email || profile.name)}</div>
          <div className="who">
            <div className="who-name">{profile.name || 'Unnamed'}</div>
            <div className="who-meta">{profile.email || 'no email'} · <span className="plan">{profile.plan}</span></div>
          </div>
        </div>
      </div>

      <div className="settings-layout">
        <nav className="settings-tabs">
          {[
            { id: 'sites',         label: 'Sites',         sub: `${profile.sites?.length || 0} tracked` },
            { id: 'you',           label: 'You',           sub: 'Account' },
            { id: 'integrations',  label: 'Integrations',  sub: 'GitHub · Any Website' },
            { id: 'notifications', label: 'Notifications', sub: 'Daily, weekly, threshold' },
            { id: 'data',          label: 'Data',          sub: 'Export · sign out' },
          ].map(t => (
            <button
              key={t.id}
              className={`s-tab ${tab === t.id ? 'on' : ''}`}
              onClick={() => setTab(t.id)}
            >
              <span className="s-tab-label">{t.label}</span>
              <span className="s-tab-sub">{t.sub}</span>
            </button>
          ))}
        </nav>

        <div className="settings-body">
          {tab === 'sites' && (
            <SettingsSites
              profile={profile}
              activeSite={activeSite}
              updateSiteById={updateSiteById}
              addSite={addSite}
              onAddAndScan={onAddAndScan}
              removeSite={removeSite}
              setActiveSite={setActiveSite}
            />
          )}
          {tab === 'you' && (
            <SettingsYou profile={profile} update={update} />
          )}
          {tab === 'integrations' && (
            <SettingsIntegrations profile={profile} updateActiveSite={updateActiveSite} />
          )}
          {tab === 'notifications' && (
            <SettingsNotifications profile={profile} updateNotifications={updateNotifications} />
          )}
          {tab === 'data' && (
            <SettingsData profile={profile} signOut={signOut} />
          )}
        </div>
      </div>
    </section>
  );
}

function SettingsYou({ profile, update }) {
  const user = window.supaCurrentUser ? window.supaCurrentUser() : null;
  const authed = !!(window.supaIsAuthed && window.supaIsAuthed()) && !!user;
  const [pw, setPw] = React.useState('');
  const [msg, setMsg] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const signOut = () => { try { window.supaSignOut && window.supaSignOut(); } catch {} location.reload(); };
  async function savePw() {
    if (pw.length < 6) { setMsg({ t: 'err', m: 'At least 6 characters.' }); return; }
    setBusy(true); setMsg(null);
    try { await window.supaSetPassword(pw); setPw(''); setMsg({ t: 'ok', m: 'Saved — you can sign in with this password too.' }); }
    catch (e) { setMsg({ t: 'err', m: e.message }); } finally { setBusy(false); }
  }
  async function deleteAccount() {
    if (!window.confirm('Permanently delete your account and all cloud data? This cannot be undone.')) return;
    setBusy(true);
    try {
      const s = window.supaLoad ? window.supaLoad() : {};
      const r = await fetch('/api/delete-account', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ access_token: s.session && s.session.access_token }) });
      if (!r.ok) throw new Error('delete failed');
      try { window.supaSignOut && window.supaSignOut(); } catch {}
      location.reload();
    } catch (e) { window.aisoToast('Could not delete account: ' + (e.message || e), 'error'); setBusy(false); }
  }
  const inp = { width: '100%', padding: '11px 13px', borderRadius: 9, border: '1px solid var(--line)', background: 'var(--bg-2)', color: 'var(--fg-0)', fontSize: 14, outline: 'none' };
  return (
    <div className="s-pane">
      <h2 className="s-h">Account</h2>
      {authed ? (
        <div style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '14px 16px', border: '1px solid var(--line)', borderRadius: 12, background: 'var(--bg-2)', marginBottom: 22 }}>
          <span style={{ width: 40, height: 40, borderRadius: '50%', background: 'var(--accent-grad, var(--accent))', display: 'grid', placeItems: 'center', color: '#0b0c10', fontWeight: 700, flexShrink: 0 }}>{(user.email || '?')[0].toUpperCase()}</span>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontWeight: 600, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{user.email}</div>
            <div style={{ fontSize: 12, color: 'var(--good, #5ad08a)', fontFamily: 'var(--mono)' }}>● Signed in · {profile.plan || 'Free'} · synced to cloud</div>
          </div>
          <button className="btn btn-ghost" onClick={signOut} style={{ flexShrink: 0 }}>Sign out</button>
        </div>
      ) : (
        <div style={{ padding: 18, border: '1px solid var(--line)', borderRadius: 12, background: 'var(--bg-2)', marginBottom: 22 }}>
          <div style={{ fontWeight: 600, fontSize: 15, marginBottom: 4 }}>You're not signed in</div>
          <div style={{ color: 'var(--fg-2)', fontSize: 13.5, lineHeight: 1.5, marginBottom: 14 }}>Your data lives only in this browser. Sign in with your email — we send a 6-digit code, no password needed — to sync your sites + scans across devices.</div>
          <button className="btn btn-primary" onClick={() => window.aisoOpenAuth && window.aisoOpenAuth()}>Sign in / Create account →</button>
        </div>
      )}

      <p className="s-help">Display name used in digests and notifications.</p>
      <div className="s-grid">
        <Field label="Name" value={profile.name} onChange={(v) => update({ name: v })} placeholder="Your name" />
        {!authed && <Field label="Email" value={profile.email} onChange={(v) => update({ email: v })} placeholder="you@brand.com" type="email" />}
      </div>

      {authed && (
        <>
          <h2 className="s-h" style={{ marginTop: 28 }}>Password (optional)</h2>
          <p className="s-help">You sign in with an email code by default. Set a password if you'd like that option too.</p>
          <form onSubmit={(e) => { e.preventDefault(); savePw(); }} style={{ maxWidth: 440 }}>
            {/* hidden username so password managers store the credential against your email */}
            <input type="email" autoComplete="username" value={user.email || ''} readOnly tabIndex={-1} aria-hidden="true" style={{ position: 'absolute', left: '-9999px', width: 1, height: 1, opacity: 0 }} />
            <div style={{ display: 'flex', gap: 8 }}>
              <input style={inp} type="password" value={pw} onChange={(e) => setPw(e.target.value)} placeholder="New password" autoComplete="new-password" />
              <button type="submit" className="btn" disabled={busy || pw.length < 6}>Save</button>
            </div>
          </form>
          {msg && <div style={{ marginTop: 8, fontSize: 13, color: msg.t === 'ok' ? 'var(--good, #5ad08a)' : '#f0746e' }}>{msg.m}</div>}

          <div style={{ marginTop: 28, display: 'flex', alignItems: 'center', gap: 12, flexWrap: 'wrap' }}>
            <button onClick={deleteAccount} disabled={busy} style={{ background: 'none', border: '1px solid oklch(72% 0.18 22 / 0.4)', color: '#f0746e', borderRadius: 8, padding: '7px 14px', fontSize: 13, cursor: 'pointer' }}>Delete account</button>
            <span style={{ color: 'var(--fg-3)', fontSize: 12.5 }}>Permanently removes your account and all cloud data.</span>
          </div>
        </>
      )}
    </div>
  );
}

// Live open-PR manager for a site's connected repo — fetches from GitHub, closes in-app.
function SiteOpenPRs({ repo }) {
  const [prs, setPrs] = React.useState(null);
  const [busy, setBusy] = React.useState(false);
  const [closing, setClosing] = React.useState({});
  const gh = window.ghLoad ? window.ghLoad() : {};
  const load = () => {
    if (!gh.pat || !repo || !window.ghListOpenPrs) return;
    setBusy(true);
    window.ghListOpenPrs(gh.pat, repo).then(setPrs).catch(() => setPrs([])).finally(() => setBusy(false));
  };
  React.useEffect(() => { load(); }, [repo && repo.fullName, gh.pat]);
  if (!gh.pat || !repo) return null;
  async function closePr(pr) {
    if (!window.confirm(`Close PR #${pr.number}?\n\n"${pr.title}"`)) return;
    setClosing((c) => ({ ...c, [pr.number]: true }));
    try {
      await window.ghClosePr(gh.pat, repo, pr.number, pr.branch);
      setPrs((list) => (list || []).filter((p) => p.number !== pr.number));
    } catch (e) { window.aisoToast('Could not close PR: ' + (e.message || e), 'error'); }
    finally { setClosing((c) => ({ ...c, [pr.number]: false })); }
  }
  return (
    <div className="site-last-scan" style={{ marginTop: 14 }}>
      <div className="sls-eyebrow" style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <span>Open pull requests · {repo.fullName}{prs ? ` · ${prs.length}` : ''}</span>
        <button className="link-btn" onClick={load} disabled={busy}>{busy ? 'Loading…' : 'Refresh'}</button>
      </div>
      <div className="sls-body" style={{ flexDirection: 'column', alignItems: 'stretch', gap: 8 }}>
        {prs === null && <span className="sls-meta">Loading…</span>}
        {prs && prs.length === 0 && <span className="sls-meta">None open — you're clear.</span>}
        {prs && prs.map((pr) => (
          <div key={pr.number} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            <a href={pr.url} target="_blank" rel="noopener noreferrer" style={{ flex: 1, minWidth: 0, fontFamily: 'var(--mono)', fontSize: 12.5, color: 'var(--fg-1)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>#{pr.number} · {pr.title}</a>
            <button className="btn-ghost" style={{ color: '#f0746e', flexShrink: 0 }} onClick={() => closePr(pr)} disabled={closing[pr.number]}>{closing[pr.number] ? 'Closing…' : 'Close'}</button>
          </div>
        ))}
      </div>
    </div>
  );
}

function SettingsSites({ profile, activeSite, updateSiteById, addSite, onAddAndScan, removeSite, setActiveSite }) {
  const [editingId, setEditingId] = React.useState(activeSite?.id || null);
  const editing = (profile.sites || []).find((s) => s.id === editingId) || activeSite;
  const [comp, setComp] = React.useState('');
  const [newDomain, setNewDomain] = React.useState('');
  const newDomainRef = React.useRef(null);

  function quickAdd(e) {
    e?.preventDefault?.();
    const raw = newDomain.trim();
    if (!raw) return;
    if (typeof onAddAndScan === 'function') {
      const site = onAddAndScan(raw);
      if (site) {
        setEditingId(site.id);
        setNewDomain('');
      }
      return;
    }
    // Fallback (no scan available)
    const cleaned = raw.replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/.*$/, '').trim();
    if (!cleaned) return;
    const stem = cleaned.split('.')[0];
    const name = stem.charAt(0).toUpperCase() + stem.slice(1);
    const site = addSite({ name, domain: cleaned, industry: '', location: '' });
    setActiveSite(site.id);
    setEditingId(site.id);
    setNewDomain('');
  }

  return (
    <div className="s-pane">
      <div className="s-pane-head">
        <h2 className="s-h">Tracked sites</h2>
        <p className="s-help">
          Each site is a separate brand profile with its own scans, competitors, and history. Switch between them from the topbar.
        </p>
      </div>

      <div className="sites-layout">
        <div className="sites-list">
          {(profile.sites || []).map((s) => (
            <button
              key={s.id}
              className={`site-row ${editingId === s.id ? 'editing' : ''} ${activeSite?.id === s.id ? 'is-active' : ''}`}
              onClick={() => setEditingId(s.id)}
            >
              <div className="site-row-avatar">{(s.name || '·')[0].toUpperCase()}</div>
              <div className="site-row-text">
                <div className="site-row-name">{s.name || <em style={{ color: 'var(--fg-3)' }}>Untitled site</em>}</div>
                <div className="site-row-dom">{s.domain || 'no domain'}</div>
              </div>
              {activeSite?.id === s.id && <span className="site-active-tag">active</span>}
            </button>
          ))}
          <form className="site-add" onSubmit={quickAdd}>
            <span className="site-add-prefix">https://</span>
            <input
              ref={newDomainRef}
              type="text"
              className="site-add-input"
              value={newDomain}
              onChange={(e) => setNewDomain(e.target.value)}
              placeholder="yourbrand.com"
              autoComplete="off"
              spellCheck={false}
              onKeyDown={(e) => { if (e.key === 'Enter') quickAdd(e); }}
            />
            <button type="submit" className="site-add-btn" disabled={!newDomain.trim()} aria-label="Add site">
              <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round"/></svg>
            </button>
          </form>
        </div>

        <div className="site-edit">
          {!editing ? (
            <div className="site-empty">No site selected. Add one →</div>
          ) : (
            <>
              <div className="site-edit-head">
                <div>
                  <h3>{editing.name || 'Untitled'}</h3>
                  <div className="site-edit-meta">added {new Date(editing.addedAt || Date.now()).toLocaleDateString()}</div>
                </div>
                <div className="site-edit-actions">
                  {activeSite?.id !== editing.id && (
                    <button className="btn" onClick={() => setActiveSite(editing.id)}>Make active</button>
                  )}
                  {(profile.sites || []).length > 1 && (
                    <button className="btn danger" onClick={() => {
                      removeSite(editing.id);
                      setEditingId(null);
                    }}>Delete</button>
                  )}
                </div>
              </div>

              <div className="s-grid">
                <Field label="Brand name" value={editing.name} onChange={(v) => updateSiteById(editing.id, { name: v })} placeholder="What people search for" />
                <Field label="Domain" mono value={editing.domain} onChange={(v) => updateSiteById(editing.id, { domain: v.replace(/^https?:\/\//, '').replace(/\/.*$/, '') })} placeholder="brand.com" />
                <Field label="Industry" value={editing.industry} onChange={(v) => updateSiteById(editing.id, { industry: v })} placeholder="e.g. specialty coffee" />
                <Field label="Location" value={editing.location} onChange={(v) => updateSiteById(editing.id, { location: v })} placeholder="City, region" />
              </div>

              <h4 className="s-h-sub">Competitors</h4>
              <p className="s-help">We track these by name across AI responses.</p>
              <div className="comp-tags">
                {(editing.competitors || []).map((c, i) => (
                  <span key={i} className="comp-tag">
                    {c}
                    <button onClick={() => updateSiteById(editing.id, { competitors: editing.competitors.filter((_, j) => j !== i) })}>×</button>
                  </span>
                ))}
                <form
                  className="comp-add"
                  onSubmit={(e) => {
                    e.preventDefault();
                    const v = comp.trim();
                    if (!v) return;
                    updateSiteById(editing.id, { competitors: [...(editing.competitors || []), v] });
                    setComp('');
                  }}
                >
                  <input
                    value={comp}
                    onChange={(e) => setComp(e.target.value)}
                    placeholder="+ Add competitor"
                    autoComplete="off"
                  />
                </form>
              </div>

              {editing.lastScan && (
                <div className="site-last-scan">
                  <div className="sls-eyebrow">Last verified scan</div>
                  <div className="sls-body">
                    <span className="sls-score">{editing.lastScan.score}%</span>
                    <span className="sls-meta">{editing.lastScan.configured?.length || 0} models · {editing.lastScan.totalCalls} prompts · {new Date(editing.lastScan.runAt).toLocaleString()}</span>
                  </div>
                </div>
              )}

              {window.GitHubConnector && (
                <div style={{ marginTop: 16 }}>
                  <window.GitHubConnector
                    profile={profile}
                    site={editing}
                    repoOnly
                    onPickRepo={(repo) => updateSiteById(editing.id, { repo })}
                  />
                </div>
              )}

              {editing.repo && <SiteOpenPRs repo={editing.repo} />}
            </>
          )}
        </div>
      </div>
    </div>
  );
}

function SettingsIntegrations({ profile, updateActiveSite }) {
  return (
    <div className="s-pane">
      <div className="s-pane-head">
        <h2 className="s-h">Integrations</h2>
        <p className="s-help">
          Connect AISO to where your code actually lives. When you approve a fix, we ship it through these.
        </p>
      </div>

      {window.GitHubConnector && <window.GitHubConnector profile={profile} onPickRepo={(repo) => updateActiveSite && updateActiveSite({ repo })} />}

      <div className="int-soon">
        <div className="int-soon-row">
          <div className="int-soon-logo">▲</div>
          <div className="int-soon-text">
            <div className="int-soon-name">Vercel</div>
            <div className="int-soon-desc">Deploy hooks — automatic redeploy after a fix merges. <span style={{ color: 'var(--fg-3)' }}>Coming next.</span></div>
          </div>
        </div>
        <div className="int-soon-row">
          <div className="int-soon-logo">W</div>
          <div className="int-soon-text">
            <div className="int-soon-name">WordPress</div>
            <div className="int-soon-desc">Inject schema via a small AISO plugin (REST API + application password). <span style={{ color: 'var(--fg-3)' }}>Roadmap.</span></div>
          </div>
        </div>
      </div>
    </div>
  );
}

function SettingsCloud({ profile }) {
  return (
    <div className="s-pane">
      <div className="s-pane-head">
        <h2 className="s-h">Cloud sync</h2>
        <p className="s-help">
          Sign in across devices. Your sites, scan history, and time-series data live in your own Supabase project — not on our servers (because there is no "our servers"). API keys stay encrypted with a passphrase only you know.
        </p>
      </div>

      {window.SupabaseConnector && <window.SupabaseConnector profile={profile} />}
    </div>
  );
}

function SettingsNotifications({ profile, updateNotifications }) {
  const N = profile.notifications;
  return (
    <div className="s-pane">
      <h2 className="s-h">When should we ping you?</h2>
      <p className="s-help">
        We're allergic to noise. Pick what matters and we stay silent the rest of the time.
      </p>

      <div className="notif-grid">
        {[
          { k: 'email', label: 'Email digest', sub: 'Weekly summary' },
          { k: 'slack', label: 'Slack', sub: 'On material changes' },
          { k: 'push', label: 'iOS push', sub: 'Threshold-triggered' },
          { k: 'sms', label: 'SMS', sub: 'Critical only' },
        ].map((c) => (
          <button
            key={c.k}
            className={`notif-toggle ${N[c.k] ? 'on' : ''}`}
            onClick={() => updateNotifications({ [c.k]: !N[c.k] })}
          >
            <div className="nt-top">
              <span className="nt-label">{c.label}</span>
              <span className={`nt-switch ${N[c.k] ? 'on' : ''}`}><i /></span>
            </div>
            <div className="nt-sub">{c.sub}</div>
          </button>
        ))}
      </div>

      {N.slack && (
        <div style={{ marginTop: 16 }}>
          <label style={{ display: 'block', fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--fg-3)', marginBottom: 6 }}>Slack incoming webhook URL</label>
          <input
            type="text"
            value={N.slackWebhook || ''}
            onChange={(e) => updateNotifications({ slackWebhook: e.target.value.trim() })}
            placeholder="https://hooks.slack.com/services/…"
            spellCheck={false}
            autoComplete="off"
            style={{ width: '100%', padding: '10px 12px', borderRadius: 8, border: '1px solid var(--line)', background: 'var(--bg-2)', color: 'var(--fg-0)', fontFamily: 'var(--mono)', fontSize: 13 }}
          />
          <div style={{ fontSize: 12, color: 'var(--fg-3)', marginTop: 6 }}>
            Create one at api.slack.com → Incoming Webhooks. We ping it when a scan crosses your threshold.
          </div>
        </div>
      )}

      <h2 className="s-h" style={{ marginTop: 24 }}>Sensitivity</h2>
      <p className="s-help">
        Ping me only if my visibility score moves by at least <strong>{N.threshold} points</strong> or a competitor passes me.
      </p>
      <input
        type="range"
        min="1" max="20" step="1"
        value={N.threshold}
        onChange={(e) => updateNotifications({ threshold: Number(e.target.value) })}
        className="threshold"
      />
      <div className="threshold-ticks">
        <span>noisy · 1pt</span>
        <span style={{ color: 'var(--fg-1)' }}>{N.threshold} points</span>
        <span>quiet · 20pt</span>
      </div>
    </div>
  );
}

function SettingsData({ profile, signOut }) {
  const [confirmReset, setConfirmReset] = React.useState(false);

  function downloadJson() {
    const blob = new Blob([JSON.stringify(profile, null, 2)], { type: 'application/json' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = `aiso-profile-${new Date().toISOString().slice(0, 10)}.json`;
    a.click();
    URL.revokeObjectURL(url);
  }

  return (
    <div className="s-pane">
      <h2 className="s-h">Your data</h2>
      <p className="s-help">
        Everything you've configured lives in your browser. Below is the full record, exactly as we have it.
      </p>

      <pre className="data-pre">{JSON.stringify({
        ...profile,
        keys: Object.fromEntries(Object.entries(profile.keys).map(([k, v]) => [k, v ? '••••••••' + (v.slice(-4) || '') : ''])),
      }, null, 2)}</pre>

      <div className="data-actions">
        <button className="btn" onClick={downloadJson}>Download as JSON</button>
        {!confirmReset ? (
          <button className="btn danger" onClick={() => setConfirmReset(true)}>Sign out & erase</button>
        ) : (
          <>
            <button className="btn danger-strong" onClick={signOut}>Confirm — wipe everything</button>
            <button className="btn ghost" onClick={() => setConfirmReset(false)}>Cancel</button>
          </>
        )}
      </div>
    </div>
  );
}

function Field({ label, value, onChange, placeholder, type = 'text', mono = false }) {
  return (
    <label className={`field ${mono ? 'mono' : ''}`}>
      <span className="field-label">{label}</span>
      <input
        type={type}
        value={value || ''}
        onChange={(e) => onChange(e.target.value)}
        placeholder={placeholder}
        autoComplete="off"
        spellCheck={false}
      />
    </label>
  );
}

/* ---------- Onboarding modal (first run) ---------- */
function Onboarding({ open, onDone, onSkip, profile, update, updateActiveSite }) {
  const [email, setEmail] = React.useState(profile.email || '');
  const active = getActiveSite(profile);
  const [brand, setBrand] = React.useState(active?.name || '');
  const [domain, setDomain] = React.useState(active?.domain || '');

  if (!open) return null;

  function finish() {
    const cleanedDomain = (domain || active?.domain || '').replace(/^https?:\/\//, '').replace(/\/.*$/, '').trim();
    update({ email, name: email ? email.split('@')[0] : profile.name });
    if (active) {
      updateActiveSite({
        name: brand || active.name,
        domain: cleanedDomain || active.domain,
      });
    }
    // Pass back what the user typed so the App can sync the landing input
    // without waiting for the next state batch.
    onDone({ name: brand || active?.name, domain: cleanedDomain || active?.domain });
  }

  return (
    <div className="onboarding-overlay" onClick={(e) => { if (e.target === e.currentTarget) onSkip(); }}>
      <div className="onboarding">
        <div className="ob-head">
          <div className="ob-eyebrow"><span className="pulse" /> First-time setup · 30 seconds</div>
          <h2>Make AISO yours.</h2>
        </div>
        <div className="ob-body">
          <Field label="Email (we'll use it to find you again)" value={email} onChange={setEmail} placeholder="you@brand.com" type="email" />
          <Field label="Brand name" value={brand} onChange={setBrand} placeholder="What people search for" />
          <Field label="Domain" value={domain} onChange={setDomain} placeholder="brand.com" mono />
        </div>
        <div className="ob-foot">
          <button className="btn ghost" onClick={onSkip}>Skip — I'll do it later</button>
          <button className="btn btn-primary" onClick={finish} disabled={!email && !brand}>
            Start <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>
          </button>
        </div>
      </div>
    </div>
  );
}

/* ---------- SiteSwitcher — topbar dropdown ---------- */
function SiteSwitcher({ profile, activeSite, setActiveSite, addSite, onSelectSite, onOpenSettings }) {
  const [open, setOpen] = React.useState(false);
  const [newDomain, setNewDomain] = React.useState('');
  const ref = React.useRef(null);
  const inputRef = React.useRef(null);

  function quickAdd(e) {
    e?.preventDefault?.();
    const raw = newDomain.trim();
    if (!raw) return;
    const cleaned = raw.replace(/^https?:\/\//, '').replace(/^www\./, '').replace(/\/.*$/, '').trim();
    if (!cleaned) return;
    const stem = cleaned.split('.')[0];
    const name = stem.charAt(0).toUpperCase() + stem.slice(1);
    const site = addSite({ name, domain: cleaned, industry: '', location: '' });
    setActiveSite(site.id);
    setNewDomain('');
    setOpen(false);
  }

  React.useEffect(() => {
    if (!open) return;
    function onDoc(e) {
      if (ref.current && !ref.current.contains(e.target)) setOpen(false);
    }
    document.addEventListener('mousedown', onDoc);
    return () => document.removeEventListener('mousedown', onDoc);
  }, [open]);

  if (!activeSite) return null;

  return (
    <div className="site-switcher" ref={ref}>
      <button className={`switch-trigger ${open ? 'on' : ''}`} onClick={() => setOpen((o) => !o)}>
        <span className="switch-avatar">{(activeSite.name || '·')[0].toUpperCase()}</span>
        <span className="switch-text">
          <span className="switch-name">{activeSite.name || 'Untitled'}</span>
          <span className="switch-dom">{activeSite.domain}</span>
        </span>
        <svg className="switch-chev" width="10" height="10" viewBox="0 0 10 10" fill="none">
          <path d="M2 3.5l3 3 3-3" stroke="currentColor" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
        </svg>
      </button>
      {open && (
        <div className="switch-menu">
          <div className="switch-menu-head">Tracked sites · {profile.sites?.length || 0}</div>
          <div className="switch-menu-list">
            {(profile.sites || []).map((s) => (
              <button
                key={s.id}
                className={`switch-item ${s.id === activeSite.id ? 'on' : ''}`}
                onClick={() => { (onSelectSite ? onSelectSite(s) : setActiveSite(s.id)); setOpen(false); }}
              >
                <span className="switch-avatar">{(s.name || '·')[0].toUpperCase()}</span>
                <span className="switch-text">
                  <span className="switch-name">{s.name || 'Untitled'}</span>
                  <span className="switch-dom">{s.domain || 'no domain'}</span>
                </span>
                <span style={{ marginLeft: 'auto', display: 'flex', alignItems: 'center', gap: 6 }}>
                  {s.repo && (
                    <span title={`Connected to ${s.repo.fullName}`} style={{ fontFamily: 'var(--mono)', fontSize: 9.5, letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--good)', border: '1px solid oklch(82% 0.16 152 / 0.45)', borderRadius: 999, padding: '2px 7px' }}>✓ mine</span>
                  )}
                  <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', color: (s.lastScan || s.discovered) ? 'var(--good)' : 'var(--accent)', border: '1px solid var(--line)', borderRadius: 999, padding: '2px 9px' }}>
                    {(s.lastScan || s.discovered) ? 'View' : 'Scan'}
                  </span>
                </span>
              </button>
            ))}
          </div>
          <div className="switch-menu-foot">
            <form className="switch-add" onSubmit={quickAdd}>
              <span className="switch-add-prefix">https://</span>
              <input
                ref={inputRef}
                type="text"
                className="switch-add-input"
                value={newDomain}
                onChange={(e) => setNewDomain(e.target.value)}
                placeholder="yourbrand.com"
                autoComplete="off"
                spellCheck={false}
                onKeyDown={(e) => { if (e.key === 'Enter') quickAdd(e); }}
              />
              <button type="submit" className="switch-add-btn" disabled={!newDomain.trim()} aria-label="Add site">
                <svg width="12" height="12" viewBox="0 0 14 14" fill="none"><path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/></svg>
              </button>
            </form>
            <button className="switch-action" onClick={() => { setOpen(false); onOpenSettings(); }}>
              <Cog /> Manage
            </button>
          </div>
        </div>
      )}
    </div>
  );
}

Object.assign(window, {
  useProfile, Settings, Onboarding, SiteSwitcher, initials, Cog, defaultProfile, getActiveSite,
});
