// Institutional CRM — App shell: topbar, nav, subnav, mobile tab bar, routing
const NAV_GROUPS = [
  { label: 'Dashboard', pages: ['Dashboard'] },
  { label: 'Growth', pages: ['Leads', 'Sources', 'Partners'] },
  { label: 'Funding', pages: ['Deals', 'Brokered', 'Calculator', 'Syndication'] },
  { label: 'Settlement', pages: ['Settlements'] },
  { label: 'Money', pages: ['Commissions', 'Portfolio'] },
  { label: 'Clients', pages: ['Clients'] },
];
const PAGE_LABEL = { Dashboard: 'Overview', Leads: 'Lead funnel', Sources: 'Lead sources', Partners: 'Referral partners', Deals: 'Deals', Calculator: 'Offer calculator', Syndication: 'Syndication', Brokered: 'Brokered deals', Settlements: 'Settlement casefiles', Commissions: 'Commissions', Portfolio: 'Portfolio', Clients: 'Clients' };

function groupOf(page) { return NAV_GROUPS.find(g => g.pages.includes(page)) || NAV_GROUPS[0]; }

// URL hash ↔ view: '#Deals/EF-26-975' opens that file directly; bookmarkable / shareable / refresh-safe
function parseHash() {
  const h = decodeURIComponent((window.location.hash || '').slice(1));
  if (!h) return { page: 'Dashboard', id: null };
  const parts = h.split('/');
  return { page: PAGE_LABEL[parts[0]] ? parts[0] : 'Dashboard', id: parts[1] || null };
}

function CrmShell() {
  const init = React.useMemo(parseHash, []);
  const [page, setPage] = React.useState(init.page);
  const [dealId, setDealId] = React.useState(init.id);
  const [leads, setLeads] = React.useState(window.ICRM.LEADS);
  const [openAddLead, setOpenAddLead] = React.useState(false);
  const [leadBrand, setLeadBrand] = React.useState({ v: '' });
  const { msg, toast } = useToastI();

  // keep the shared LEADS in sync so dashboard funnel reflects changes
  window.ICRM.LEADS = leads;

  // live mode: hydrate leads from the backend once it answers (2.* walkthrough builds have no JSON API — skipped)
  React.useEffect(() => {
    fetch('/api/leads').then(async (r) => {
      if (!r.ok || !(r.headers.get('Content-Type') || '').includes('json')) return;
      const d = await r.json().catch(() => null);
      if (d && Array.isArray(d.leads)) {
        setLeads(d.leads.map(x => ({
          id: x.public_id, biz: x.biz || 'Untitled Business', owner: x.owner || '', phone: x.phone || '', email: x.email || '',
          amount: x.amount || 0, stage: x.stage || 'New', brand: x.brand || 'ExpressFund',
          sourceId: x.source_id, auto: !!x.auto, intake: x.intake || undefined,
          received: (x.created_at || '').slice(0, 10) || '—',
        })));
      }
    }).catch(() => {});
  }, []);

  const scrollMem = React.useRef({});
  const go = (p, id, openAdd, brand) => {
    if (id && page === p && !dealId) scrollMem.current[p] = window.scrollY;
    setPage(p); setDealId(id || null);
    if (openAdd) setOpenAddLead(true);
    if (brand !== undefined) setLeadBrand({ v: brand });
    const target = '#' + p + (id ? '/' + id : '');
    if (window.location.hash !== target) window.location.hash = target;
  };
  // back/forward buttons + hand-edited URLs
  React.useEffect(() => {
    const onHash = () => { const h = parseHash(); setPage(h.page); setDealId(h.id); };
    window.addEventListener('hashchange', onHash);
    return () => window.removeEventListener('hashchange', onHash);
  }, []);
  // file pages open at the top; returning to a list restores where you left off
  React.useEffect(() => { window.scrollTo(0, dealId ? 0 : (scrollMem.current[page] || 0)); }, [page, dealId]);

  const grp = groupOf(page);

  const TABS = [
    { label: 'Dashboard', page: 'Dashboard', icon: ICONS.home },
    { label: 'Leads', page: 'Leads', icon: ICONS.funnel },
    { label: 'Deals', page: 'Deals', icon: ICONS.deals },
    { label: 'Clients', page: 'Clients', icon: ICONS.clients },
    { label: 'More', page: 'Portfolio', icon: ICONS.more },
  ];

  return (
    <div style={{ minHeight: '100vh', background: 'var(--inst-canvas)' }} data-screen-label={'CRM — ' + page}>
      <Toast msg={msg} />
      <header className="inst-topbar">
        <span className="inst-brandmark">
          <EFWordmark light />
          <span className="suffix">CONNECT</span>
        </span>
        <span className="spacer"></span>
        <button title="Search" style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', padding: 6 }}><IC d={ICONS.search} /></button>
        <button title="Alerts" style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', padding: 6 }}><IC d={ICONS.bell} /></button>
        <button title="Profile" style={{ background: 'none', border: 'none', color: '#fff', cursor: 'pointer', padding: 6 }}><IC d={ICONS.user} /></button>
        <button className="inst-btn primary sm" onClick={() => go('Calculator')}>New offer</button>
        <a className="inst-link" style={{ color: '#fff', fontSize: 12 }} onClick={() => fetch('/api/auth/logout', { method: 'POST' }).catch(() => {}).then(() => window.location.reload())}>Sign out</a>
      </header>

      <nav className="inst-nav">
        {NAV_GROUPS.map(g => (
          <a key={g.label} className={grp.label === g.label ? 'active' : ''} onClick={() => go(g.pages[0])}>{g.label}</a>
        ))}
      </nav>

      {grp.pages.length > 1 ? (
        <div className="inst-subnav">
          {grp.pages.map(p => (
            <a key={p} className={page === p ? 'active' : ''} onClick={() => go(p)}>{PAGE_LABEL[p]}</a>
          ))}
        </div>
      ) : null}

      {page === 'Dashboard' ? <PgDashboard go={go} /> : null}
      {page === 'Leads' ? <PgLeads leads={leads} setLeads={setLeads} openAdd={openAddLead} setOpenAdd={setOpenAddLead} initBrand={leadBrand} toast={toast} /> : null}
      {page === 'Sources' ? <PgSources toast={toast} /> : null}
      {page === 'Partners' ? <PgPartners toast={toast} /> : null}
      {page === 'Deals' ? <PgDeals fileId={dealId} go={go} /> : null}
      {page === 'Brokered' ? <PgBrokered fileId={dealId} go={go} toast={toast} /> : null}
      {page === 'Settlements' ? <PgSettlements fileId={dealId} go={go} /> : null}
      {page === 'Calculator' ? <PgCalculator toast={toast} /> : null}
      {page === 'Syndication' ? <PgSyndication /> : null}
      {page === 'Commissions' ? <PgCommissions toast={toast} /> : null}
      {page === 'Portfolio' ? <PgPortfolio /> : null}
      {page === 'Clients' ? <PgClients /> : null}

      <nav className="inst-tabbar">
        {TABS.map(t => (
          <button key={t.label} className={groupOf(page).pages.includes(t.page) || page === t.page ? 'active' : ''} onClick={() => go(t.page)}>
            <IC d={t.icon} size={20} />
            {t.label}
          </button>
        ))}
      </nav>
    </div>
  );
}


// ── Real sign-in (activates automatically once the phase-2 backend + D1 are deployed) ──
function AdminLogin({ onDone, setupRequired, pending, totpSetup }) {
  const [step, setStep] = React.useState(setupRequired ? 'setup' : pending ? 'code' : 'creds');
  const [email, setEmail] = React.useState('');
  const [pw, setPw] = React.useState('');
  const [name, setName] = React.useState('');
  const [code, setCode] = React.useState('');
  const [totp, setTotp] = React.useState(null);
  const [err, setErr] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const post = async (p, b) => { const r = await fetch(p, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(b) }); return { ok: r.ok, data: await r.json().catch(() => ({})) }; };
  const beginTotp = async () => { const r = await post('/api/auth/totp/setup', {}); if (r.ok) { setTotp(r.data); setStep('totp-setup'); setCode(''); } else onDone(); };
  React.useEffect(() => { if (totpSetup) beginTotp(); }, []);
  const submit = async (e) => {
    e.preventDefault(); setErr(''); setBusy(true);
    try {
      if (step === 'setup') { const r = await post('/api/setup', { email, password: pw, name }); if (!r.ok) { setErr(r.data.error || 'Setup failed'); return; } await beginTotp(); return; }
      if (step === 'creds') { const r = await post('/api/auth/login', { email, password: pw }); if (!r.ok) { setErr(r.data.error || 'Invalid email or password'); return; }
        if (r.data.stage === 'pending_2fa') { setStep('code'); setCode(''); } else if (r.data.needsTotpSetup) { await beginTotp(); } else { onDone(); } return; }
      if (step === 'code') { const r = await post('/api/auth/verify', { code }); if (!r.ok) { setErr('Code did not match — try again'); return; } onDone(); return; }
      if (step === 'totp-setup') { const r = await post('/api/auth/totp/enable', { code }); if (!r.ok) { setErr('Code did not match — try again'); return; } onDone(); return; }
    } finally { setBusy(false); }
  };
  return (
    <div style={{ minHeight: '100vh', background: 'linear-gradient(180deg, var(--inst-navy) 0%, var(--inst-navy-deep) 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }} data-screen-label="CRM — Sign in">
      <div style={{ width: '100%', maxWidth: 420 }}>
        <div style={{ textAlign: 'center', marginBottom: 22 }}>
          <EFWordmark light size={24} /> <span style={{ color: 'rgba(255,255,255,.8)', fontSize: 11, fontWeight: 600, letterSpacing: 2, marginLeft: 6 }}>CONNECT</span>
        </div>
        <form style={{ background: '#fff', borderRadius: 8, padding: '28px 26px', display: 'grid', gap: 12 }} onSubmit={submit}>
          {step === 'setup' ? <React.Fragment>
            <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--inst-ink)' }}>Create the first admin account</div>
            <div style={{ fontSize: 12, color: 'var(--inst-ink-3)' }}>Fresh database — this screen only appears once.</div>
            <div className="inst-field"><label>Your name</label><input className="inst-input" value={name} onChange={e => setName(e.target.value)} /></div>
            <div className="inst-field"><label>Email</label><input className="inst-input" type="email" value={email} onChange={e => setEmail(e.target.value)} /></div>
            <div className="inst-field"><label>Password (10+ characters)</label><input className="inst-input" type="password" value={pw} onChange={e => setPw(e.target.value)} /></div>
          </React.Fragment> : null}
          {step === 'creds' ? <React.Fragment>
            <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--inst-ink)' }}>Sign in</div>
            <div className="inst-field"><label>Email</label><input className="inst-input" type="email" value={email} onChange={e => setEmail(e.target.value)} autoFocus /></div>
            <div className="inst-field"><label>Password</label><input className="inst-input" type="password" value={pw} onChange={e => setPw(e.target.value)} /></div>
          </React.Fragment> : null}
          {step === 'code' ? <React.Fragment>
            <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--inst-ink)' }}>Two-step verification</div>
            <div style={{ fontSize: 12, color: 'var(--inst-ink-3)' }}>Enter the 6-digit code from your authenticator app.</div>
            <input className="inst-input" inputMode="numeric" maxLength={6} style={{ fontSize: 22, letterSpacing: 8, textAlign: 'center', fontWeight: 700 }} value={code} onChange={e => setCode(e.target.value.replace(/[^0-9]/g, ''))} autoFocus />
          </React.Fragment> : null}
          {step === 'totp-setup' ? <React.Fragment>
            <div style={{ fontSize: 18, fontWeight: 800, color: 'var(--inst-ink)' }}>Protect this account with 2FA</div>
            <div style={{ fontSize: 12, color: 'var(--inst-ink-2)', lineHeight: 1.6 }}>Add the account to Google Authenticator, 1Password or Authy, then enter the 6-digit code it shows.</div>
            {totp ? <React.Fragment>
              <a className="inst-btn outline" style={{ width: '100%' }} href={totp.otpauth}>Open in authenticator app</a>
              <div style={{ fontSize: 11, color: 'var(--inst-ink-3)' }}>Or enter this key manually:</div>
              <code style={{ fontSize: 13, background: 'var(--brand-50)', border: '1px solid #c8d9f2', borderRadius: 4, padding: '8px 10px', wordBreak: 'break-all', color: 'var(--inst-ink)' }}>{totp.secret}</code>
            </React.Fragment> : null}
            <input className="inst-input" inputMode="numeric" maxLength={6} style={{ fontSize: 22, letterSpacing: 8, textAlign: 'center', fontWeight: 700 }} placeholder="000000" value={code} onChange={e => setCode(e.target.value.replace(/[^0-9]/g, ''))} />
          </React.Fragment> : null}
          {err ? <div style={{ fontSize: 12, color: 'var(--inst-neg)', fontWeight: 600 }}>{err}</div> : null}
          <button type="submit" className="inst-btn primary" style={{ width: '100%', padding: '11px 18px' }} disabled={busy}>
            {step === 'setup' ? 'Create admin account' : step === 'creds' ? 'Sign in' : step === 'code' ? 'Verify' : 'Enable 2FA & continue'}
          </button>
        </form>
      </div>
    </div>
  );
}

function AuthGate() {
  const [st, setSt] = React.useState({ mode: 'checking' });
  const check = () => fetch('/api/auth/me').then(async (r) => {
    const ct = r.headers.get('Content-Type') || '';
    if (!ct.includes('json')) { setSt({ mode: 'app', proto: true }); return; } // no backend deployed — prototype mode
    const d = await r.json().catch(() => ({}));
    if (r.status === 200) {
      if (d.stage === 'active' && !d.needsTotpSetup) { setSt({ mode: 'app', user: d.user }); return; }
      if (d.stage === 'active' && d.needsTotpSetup) { setSt({ mode: 'login', totpSetup: true }); return; }
      setSt({ mode: 'login', pending: true }); return;
    }
    if (r.status === 401) { setSt({ mode: 'login', setupRequired: !!d.setupRequired }); return; }
    setSt({ mode: 'app', proto: true });
  }).catch(() => setSt({ mode: 'app', proto: true }));
  React.useEffect(() => { check(); }, []);
  if (st.mode === 'checking') return <div style={{ minHeight: '100vh', background: 'var(--inst-canvas)' }}></div>;
  if (st.mode === 'login') return <AdminLogin setupRequired={st.setupRequired} pending={st.pending} totpSetup={st.totpSetup} onDone={check} />;
  return <CrmShell></CrmShell>;
}

ReactDOM.createRoot(document.getElementById('root')).render(<AuthGate></AuthGate>);
