// client-shell.jsx — The authenticated client portal: sidebar + scoped screens.
// Everything here is filtered to the signed-in customer's own jobs only.

function ClientShell() {
  const { client, doLogout, toast } = useClient();
  const { tweaks } = useTweakValues();
  const [screen, setScreen] = useState('overview');

  // Handle Stripe payment success/cancel redirects
  useEffect(() => {
    const params = new URLSearchParams(window.location.search);
    const paymentStatus = params.get('payment');
    if (paymentStatus === 'success') {
      toast('Payment submitted successfully. Your invoice will be updated shortly.', 'success', 5000);
      // Switch to invoices tab so they can see the updated status
      setScreen('invoices');
    } else if (paymentStatus === 'canceled') {
      toast('Payment was canceled.', 'info', 4000);
    }
    // Clear the query params from the URL to avoid re-triggering on refresh
    if (paymentStatus) {
      const url = window.location.pathname + window.location.hash;
      window.history.replaceState({}, '', url);
    }
  }, []);

  const nav = [
    { id: 'overview', label: 'Overview', icon: <IconHome size={18} /> },
    { id: 'crews', label: 'Crews on site', icon: <IconUsersBig size={18} /> },
    { id: 'compliance', label: 'Compliance', icon: <IconShield size={18} /> },
    { id: 'invoices', label: 'Invoices', icon: <IconDollar size={18} /> },
  ];

  return (
    <>
      <aside style={{ width: 230, flexShrink: 0, background: '#0E1622', color: 'rgba(255,255,255,0.85)', display: 'flex', flexDirection: 'column', padding: 14 }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 6px 16px' }}>
          <div style={{ width: 34, height: 34, borderRadius: 9, background: '#0F172A', border: '1px solid rgba(255,255,255,0.1)', display: 'grid', placeItems: 'center', fontWeight: 700, fontSize: 12, position: 'relative', overflow: 'hidden' }}>
            <div style={{ position: 'absolute', inset: 0, background: 'var(--accent)', clipPath: 'polygon(0 100%, 100% 100%, 100% 58%, 0 90%)' }} />
            <span style={{ position: 'relative', zIndex: 1 }}>{(tweaks.companyName||'RF').split(/\s+/).map(w=>w[0]).join('').slice(0,2).toUpperCase()}</span>
          </div>
          <div style={{ minWidth: 0 }}>
            <div style={{ fontWeight: 700, fontSize: 13, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{tweaks.companyName}</div>
            <div style={{ fontSize: 10.5, color: 'rgba(255,255,255,0.5)' }}>Client Portal</div>
          </div>
        </div>

        {/* Customer chip */}
        <div style={{ background: 'rgba(255,255,255,0.05)', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 10, padding: '10px 12px', marginBottom: 16, display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 34, height: 34, borderRadius: 8, background: '#fff', color: '#0F172A', display: 'grid', placeItems: 'center', fontWeight: 700, fontSize: 11, fontFamily: 'var(--font-mono)' }}>{client.logo}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div style={{ fontSize: 12.5, fontWeight: 600, color: '#fff', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{client.name}</div>
            <div style={{ fontSize: 10.5, color: 'rgba(255,255,255,0.5)' }}>Partner since 2021</div>
          </div>
        </div>

        <nav style={{ display: 'flex', flexDirection: 'column', gap: 3 }}>
          {nav.map(n => {
            const on = screen === n.id;
            return (
              <button key={n.id} onClick={() => setScreen(n.id)} style={{
                display: 'flex', alignItems: 'center', gap: 11, padding: '10px 12px',
                background: on ? 'rgba(255,255,255,0.08)' : 'transparent',
                border: 'none', borderLeft: on ? '3px solid var(--accent)' : '3px solid transparent',
                borderRadius: 8, cursor: 'pointer', textAlign: 'left', color: on ? '#fff' : 'rgba(255,255,255,0.65)',
              }}>
                <span style={{ color: on ? 'var(--accent)' : 'rgba(255,255,255,0.5)' }}>{n.icon}</span>
                <span style={{ flex: 1, fontSize: 13.5, fontWeight: on ? 600 : 500 }}>{n.label}</span>
              </button>
            );
          })}
        </nav>

        <div style={{ flex: 1 }} />
        <div style={{ fontSize: 10.5, color: 'rgba(255,255,255,0.35)', padding: '0 6px 10px', lineHeight: 1.5 }}>
          You only see work for {client.name}. Other customers' data is never shown.
        </div>
        <button onClick={doLogout} style={{ padding: '9px 12px', background: 'transparent', border: '1px solid rgba(255,255,255,0.1)', borderRadius: 9, color: 'rgba(255,255,255,0.7)', fontSize: 12.5, fontWeight: 500 }}>Sign out</button>
      </aside>

      <main style={{ flex: 1, overflowY: 'auto', padding: '28px 32px 48px', background: 'var(--bg)', position: 'relative' }}>
        {screen === 'overview' && <ClientOverview go={setScreen} />}
        {screen === 'crews' && <ClientCrews />}
        {screen === 'compliance' && <ClientCompliance />}
        {screen === 'invoices' && <ClientInvoices />}
      </main>

      <ClientDocHost />
      <div style={{ position: 'absolute', bottom: 20, right: 20, display: 'flex', flexDirection: 'column', gap: 8, zIndex: 700 }}>
        <ClientToasts />
      </div>
    </>
  );
}

function ClientToasts() {
  const { toasts } = useClient();
  return toasts.map(t => (
    <div key={t.id} className="anim-up" style={{ background: t.kind === 'success' ? 'var(--good)' : '#0F172A', color: '#fff', padding: '11px 16px', borderRadius: 10, fontSize: 13, fontWeight: 500, boxShadow: 'var(--shadow-lg)', display: 'flex', alignItems: 'center', gap: 8 }}>
      <IconCheckCircle size={16} /> {t.text}
    </div>
  ));
}

function ClientDocHost() {
  const { activeDoc, setActiveDoc } = useClient();
  if (!activeDoc) return null;
  return (
    <DocViewer open={true} onClose={() => setActiveDoc(null)} title={activeDoc.title} subtitle={activeDoc.subtitle} file={activeDoc.file} accent="var(--accent)">
      {activeDoc.el === 'invoice' && <InvoiceDoc data={activeDoc.payload} />}
    </DocViewer>
  );
}

// ── Small UI bits ────────────────────────────────────────────
function CCard({ children, style, pad = 18, onClick }) {
  return <div onClick={onClick} style={{ background: 'var(--panel)', border: '1px solid var(--line)', borderRadius: 14, padding: pad, boxShadow: 'var(--shadow-sm)', cursor: onClick ? 'pointer' : 'default', ...style }}>{children}</div>;
}
function CPill({ tone = 'neutral', children, icon }) {
  const t = { good:['var(--good-soft)','var(--good)'], warn:['var(--warn-soft)','var(--warn)'], bad:['var(--bad-soft)','var(--bad)'], info:['var(--info-soft)','var(--info)'], accent:['var(--accent-soft)','var(--accent-deep)'], neutral:['var(--panel-3)','var(--text-2)'], dark:['#0F172A','#fff'] }[tone] || ['var(--panel-3)','var(--text-2)'];
  return <span style={{ display: 'inline-flex', alignItems: 'center', gap: 5, padding: '2px 10px', borderRadius: 100, background: t[0], color: t[1], fontSize: 11.5, fontWeight: 600, whiteSpace: 'nowrap' }}>{icon}{children}</span>;
}
function CStat({ label, value, sub, tone, icon }) {
  return (
    <CCard>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 8 }}>
        <span className="eyebrow">{label}</span>{icon && <span style={{ color: tone==='accent'?'var(--accent)':'var(--muted)' }}>{icon}</span>}
      </div>
      <div className="mono tnum" style={{ fontSize: 26, fontWeight: 700, letterSpacing: -0.5, color: tone==='accent'?'var(--accent)':tone==='good'?'var(--good)':tone==='bad'?'var(--bad)':'var(--text)' }}>{value}</div>
      {sub && <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 2 }}>{sub}</div>}
    </CCard>
  );
}
function CTitle({ children, action }) {
  return <div style={{ display: 'flex', alignItems: 'baseline', justifyContent: 'space-between', marginBottom: 12, marginTop: 4 }}><h2 style={{ margin: 0, fontSize: 16, fontWeight: 700, letterSpacing: -0.2 }}>{children}</h2>{action}</div>;
}
const statusTone = { active: 'good', wrapping: 'warn', starting: 'info', paid: 'good', sent: 'info', draft: 'neutral' };
const certTone = { current: 'good', expiring: 'warn', expired: 'bad' };

// ── OVERVIEW ─────────────────────────────────────────────────
function ClientOverview({ go }) {
  const { client, jobs, invoices } = useClient();
  const onsite = jobs.reduce((s, j) => s + j.rwics.filter(r => r.onsite).length, 0);
  const active = jobs.filter(j => j.status === 'active').length;
  const certIssues = jobs.flatMap(j => j.rwics).filter(r => r.cert !== 'current').length;
  const outstanding = invoices.filter(i => i.status === 'sent').reduce((s, i) => s + i.amount, 0);

  return (
    <div className="anim-fade">
      <div style={{ marginBottom: 22 }}>
        <div className="eyebrow">{client.name} · {client.railroad}</div>
        <h1 style={{ margin: '4px 0 0', fontSize: 28, fontWeight: 700, letterSpacing: -0.6 }}>Your flagging activity</h1>
        <div style={{ fontSize: 14, color: 'var(--muted)', marginTop: 4 }}>Live view of RailFlagsPro crews protecting your right-of-way.</div>
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, marginBottom: 22 }}>
        <CStat label="RWICs on site now" value={onsite} sub="across your jobs" tone="accent" icon={<IconUsersBig size={16} />} />
        <CStat label="Active jobs" value={active} sub={`${jobs.length} total`} icon={<IconTrack size={16} />} />
        <CStat label="Compliance issues" value={certIssues} sub={certIssues ? 'needs attention' : 'all clear'} tone={certIssues ? 'bad' : 'good'} icon={<IconShield size={16} />} />
        <CStat label="Outstanding" value={C_money(outstanding)} sub="invoices sent" tone="warn" icon={<IconDollar size={16} />} />
      </div>

      <CTitle action={<button onClick={() => go('crews')} style={{ background: 'none', border: 'none', color: 'var(--accent-deep)', fontWeight: 600, fontSize: 13, cursor: 'pointer' }}>All jobs →</button>}>Active jobs</CTitle>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
        {jobs.filter(j => j.status !== 'wrapping').map(j => (
          <CCard key={j.id} pad={0}>
            <div style={{ display: 'flex', alignItems: 'center', gap: 16, padding: '14px 18px' }}>
              <div style={{ width: 48, height: 48, borderRadius: 11, background: 'var(--accent-soft)', color: 'var(--accent-deep)', display: 'grid', placeItems: 'center', flexShrink: 0 }}><IconTrack size={24} /></div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{ fontWeight: 700, fontSize: 14.5 }}>{j.name}</span>
                  <CPill tone={statusTone[j.status]}>{j.status}</CPill>
                </div>
                <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 2 }}><span className="mono">{j.projectNumber}</span> · {j.sub} · MP {j.mp} · {j.state}</div>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: -6 }}>
                {j.rwics.filter(r => r.onsite).map((r, i) => (
                  <div key={r.badge} title={r.name} style={{ width: 30, height: 30, borderRadius: 15, background: r.cert === 'current' ? 'var(--accent-soft)' : 'var(--bad-soft)', color: r.cert === 'current' ? 'var(--accent-deep)' : 'var(--bad)', display: 'grid', placeItems: 'center', fontSize: 10.5, fontWeight: 700, border: '2px solid var(--panel)', marginLeft: i === 0 ? 0 : -8 }}>{r.name.split(' ').map(w=>w[0]).join('')}</div>
                ))}
                {j.rwics.filter(r => r.onsite).length === 0 && <CPill tone="neutral">none on site</CPill>}
              </div>
            </div>
          </CCard>
        ))}
      </div>
    </div>
  );
}

// ── CREWS ────────────────────────────────────────────────────
function ClientCrews() {
  const { jobs } = useClient();
  return (
    <div className="anim-fade">
      <h1 style={{ margin: '0 0 4px', fontSize: 26, fontWeight: 700, letterSpacing: -0.5 }}>Crews on site</h1>
      <div style={{ fontSize: 14, color: 'var(--muted)', marginBottom: 22 }}>Every RWIC assigned to your projects, with live on-site status.</div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 16 }}>
        {jobs.map(j => (
          <CCard key={j.id} pad={0}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '14px 18px', borderBottom: '1px solid var(--line)' }}>
              <div>
                <div style={{ fontWeight: 700, fontSize: 14.5 }}>{j.name}</div>
                <div style={{ fontSize: 12, color: 'var(--muted)' }}><span className="mono">{j.projectNumber}</span> · {j.sub} · MP {j.mp}</div>
              </div>
              <CPill tone={statusTone[j.status]}>{j.status}</CPill>
            </div>
            {j.rwics.length === 0 ? (
              <div style={{ padding: '16px 18px', fontSize: 13, color: 'var(--muted)' }}>No RWIC assigned yet — starting {C_date(j.start)}.</div>
            ) : j.rwics.map((r, i) => (
              <div key={r.badge} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '12px 18px', borderTop: i === 0 ? 'none' : '1px solid var(--line)' }}>
                <div style={{ width: 36, height: 36, borderRadius: 18, background: 'var(--panel-3)', display: 'grid', placeItems: 'center', fontSize: 12, fontWeight: 700 }}>{r.name.split(' ').map(w=>w[0]).join('')}</div>
                <div style={{ flex: 1 }}>
                  <div style={{ fontWeight: 600, fontSize: 13.5 }}>{r.name}</div>
                  <div className="mono" style={{ fontSize: 11.5, color: 'var(--muted)' }}>{r.badge}</div>
                </div>
                <CPill tone={certTone[r.cert]}>{r.cert === 'current' ? 'Certified' : r.cert === 'expiring' ? 'Cert expiring' : 'Cert expired'}</CPill>
                {r.onsite ? <CPill tone="good"><StatusDot tone="good" size={6} pulse /> On site</CPill> : <CPill tone="neutral">Off site</CPill>}
              </div>
            ))}
          </CCard>
        ))}
      </div>
    </div>
  );
}

// ── COMPLIANCE ───────────────────────────────────────────────
function ClientCompliance() {
  const { jobs } = useClient();
  const allRwics = jobs.flatMap(j => j.rwics.map(r => ({ ...r, job: j })));
  const issues = allRwics.filter(r => r.cert !== 'current');
  const score = allRwics.length ? Math.round((allRwics.filter(r => r.cert === 'current').length / allRwics.length) * 100) : 100;
  return (
    <div className="anim-fade">
      <h1 style={{ margin: '0 0 4px', fontSize: 26, fontWeight: 700, letterSpacing: -0.5 }}>Compliance</h1>
      <div style={{ fontSize: 14, color: 'var(--muted)', marginBottom: 22 }}>FRA 49 CFR Part 214 roadway-worker certification status for crews on your property.</div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, marginBottom: 22 }}>
        <CStat label="Certification score" value={`${score}%`} sub="of crews fully current" tone={score === 100 ? 'good' : 'warn'} icon={<IconShield size={16} />} />
        <CStat label="Open issues" value={issues.length} sub={issues.length ? 'see below' : 'none'} tone={issues.length ? 'bad' : 'good'} icon={<IconAlert size={16} />} />
        <CStat label="Crews tracked" value={allRwics.length} sub="across your jobs" icon={<IconUsersBig size={16} />} />
      </div>

      {issues.length > 0 && (
        <>
          <CTitle>Needs attention</CTitle>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 10, marginBottom: 22 }}>
            {issues.map(r => (
              <CCard key={r.badge + r.job.id} style={{ borderColor: r.cert === 'expired' ? 'var(--bad)' : 'var(--warn)', borderLeftWidth: 4 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
                  <span style={{ color: r.cert === 'expired' ? 'var(--bad)' : 'var(--warn)' }}><IconAlert size={18} /></span>
                  <div style={{ flex: 1 }}>
                    <div style={{ fontWeight: 600, fontSize: 13.5 }}>{r.name} · {r.cert === 'expired' ? 'Certification expired' : 'Certification expiring soon'}</div>
                    <div style={{ fontSize: 12, color: 'var(--muted)' }}>{r.job.name} · <span className="mono">{r.badge}</span></div>
                  </div>
                  <CPill tone={certTone[r.cert]}>{r.cert}</CPill>
                </div>
              </CCard>
            ))}
          </div>
        </>
      )}

      <CTitle>Certification matrix</CTitle>
      <CCard pad={0}>
        <div style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr', gap: 10, padding: '11px 16px', background: 'var(--panel-2)', borderBottom: '1px solid var(--line)', fontSize: 10.5, fontWeight: 600, letterSpacing: 0.5, textTransform: 'uppercase', color: 'var(--muted)' }}>
          <span>RWIC</span><span>Job</span><span>Badge</span><span style={{ textAlign: 'right' }}>Status</span>
        </div>
        {allRwics.map((r, i) => (
          <div key={r.badge + r.job.id} style={{ display: 'grid', gridTemplateColumns: '1.6fr 1fr 1fr 1fr', gap: 10, padding: '11px 16px', borderTop: i === 0 ? 'none' : '1px solid var(--line)', alignItems: 'center' }}>
            <div style={{ fontWeight: 600, fontSize: 13 }}>{r.name}</div>
            <div style={{ fontSize: 12, color: 'var(--muted)' }} className="mono">{r.job.id}</div>
            <div className="mono" style={{ fontSize: 12 }}>{r.badge}</div>
            <div style={{ textAlign: 'right' }}><CPill tone={certTone[r.cert]}>{r.cert}</CPill></div>
          </div>
        ))}
      </CCard>
    </div>
  );
}

// ── Pay Invoice Modal ─────────────────────────────────────────
function PayInvoiceModal({ inv, onClose }) {
  const { client } = useClient();
  const [mode, setMode] = useState('full');
  const [partial, setPartial] = useState('');
  const [loading, setLoading] = useState(false);
  const [payError, setPayError] = useState('');

  const amountDue = inv.amount - (inv.amount_paid || 0);

  const getPayAmount = () => {
    if (mode === 'full') return amountDue;
    const v = parseFloat(partial);
    return (isNaN(v) || v <= 0) ? 0 : Math.min(v, amountDue);
  };

  const proceed = async () => {
    const amountDollars = getPayAmount();
    if (amountDollars < 0.50) {
      setPayError('Please enter an amount of at least $0.50.');
      return;
    }

    setPayError('');
    setLoading(true);

    const amountCents = Math.round(amountDollars * 100);
    const invoiceId = inv._dbId || inv.id;
    const invoiceNumber = inv.id;
    const companyName = client ? client.name : 'Client';

    try {
      // Prefer Supabase JS client functions.invoke; fall back to raw fetch
      let checkoutUrl = null;

      if (window._rfpSupabase && window._rfpSupabase.functions) {
        const { data, error } = await window._rfpSupabase.functions.invoke('create-invoice-payment', {
          body: {
            invoice_id: invoiceId,
            invoice_number: invoiceNumber,
            amount_cents: amountCents,
            company_name: companyName,
          },
        });
        if (error) throw error;
        checkoutUrl = data && data.url;
      } else {
        // Fallback: call via fetch with the Supabase anon key
        const supabaseUrl = (typeof SUPABASE_URL !== 'undefined' ? SUPABASE_URL : null)
          || window.RFP_CONFIG?.supabaseUrl;
        const anonKey = (typeof SUPABASE_ANON_KEY !== 'undefined' ? SUPABASE_ANON_KEY : null)
          || window.RFP_CONFIG?.anonKey;

        if (!supabaseUrl) throw new Error('Supabase URL not configured.');

        // Get auth token if available
        let authToken = anonKey;
        if (window._rfpSupabase) {
          const { data: sessionData } = await window._rfpSupabase.auth.getSession();
          if (sessionData && sessionData.session) {
            authToken = sessionData.session.access_token;
          }
        }

        const resp = await fetch(`${supabaseUrl}/functions/v1/create-invoice-payment`, {
          method: 'POST',
          headers: {
            'Content-Type': 'application/json',
            'Authorization': `Bearer ${authToken}`,
            'apikey': anonKey || '',
          },
          body: JSON.stringify({
            invoice_id: invoiceId,
            invoice_number: invoiceNumber,
            amount_cents: amountCents,
            company_name: companyName,
          }),
        });
        const json = await resp.json();
        if (!resp.ok) throw new Error(json.error || `HTTP ${resp.status}`);
        checkoutUrl = json.url;
      }

      if (!checkoutUrl) throw new Error('No checkout URL returned from payment service.');

      // Redirect to Stripe Checkout
      window.location.href = checkoutUrl;
    } catch (err) {
      console.error('Payment error:', err);
      setPayError('Unable to create payment session. Please contact your account manager.');
      setLoading(false);
    }
  };

  return (
    <div style={{ position: 'fixed', inset: 0, background: 'rgba(0,0,0,0.55)', display: 'grid', placeItems: 'center', zIndex: 9000 }} onClick={e => e.target === e.currentTarget && !loading && onClose()}>
      <div style={{ background: 'var(--panel)', borderRadius: 16, padding: 28, width: 420, boxShadow: 'var(--shadow-lg)', animation: 'slide-up 250ms ease both' }}>
        <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 18 }}>
          <div>
            <div className="eyebrow" style={{ marginBottom: 3 }}>PAY INVOICE</div>
            <div style={{ fontSize: 18, fontWeight: 700 }}>{inv.id}</div>
          </div>
          <button onClick={onClose} disabled={loading} style={{ background: 'none', border: 'none', cursor: loading ? 'not-allowed' : 'pointer', color: 'var(--muted)', fontSize: 20, lineHeight: 1, opacity: loading ? 0.4 : 1 }}>×</button>
        </div>

        <div style={{ background: 'var(--panel-2)', border: '1px solid var(--line)', borderRadius: 10, padding: '12px 16px', marginBottom: 20 }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4 }}>
            <span style={{ color: 'var(--muted)' }}>Invoice total</span>
            <span className="mono" style={{ fontWeight: 600 }}>{C_money(inv.amount)}</span>
          </div>
          {(inv.amount_paid || 0) > 0 && (
            <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 13, marginBottom: 4 }}>
              <span style={{ color: 'var(--muted)' }}>Already paid</span>
              <span className="mono" style={{ color: 'var(--good)', fontWeight: 600 }}>-{C_money(inv.amount_paid)}</span>
            </div>
          )}
          <div style={{ display: 'flex', justifyContent: 'space-between', fontSize: 14, fontWeight: 700, paddingTop: 8, borderTop: '1px solid var(--line)', marginTop: 4 }}>
            <span>Amount due</span>
            <span className="mono" style={{ color: 'var(--accent-deep)' }}>{C_money(amountDue)}</span>
          </div>
        </div>

        <div style={{ marginBottom: 20 }}>
          <label style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '12px 14px', border: `2px solid ${mode === 'full' ? 'var(--accent)' : 'var(--line)'}`, borderRadius: 9, cursor: 'pointer', marginBottom: 8, background: mode === 'full' ? 'var(--accent-soft)' : 'var(--panel)' }}>
            <input type="radio" name="paymode" checked={mode === 'full'} onChange={() => { setMode('full'); setPayError(''); }} style={{ accentColor: 'var(--accent)' }} />
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 600, fontSize: 13.5 }}>Pay in full</div>
              <div className="mono" style={{ fontSize: 12, color: 'var(--muted)' }}>{C_money(amountDue)}</div>
            </div>
          </label>
          <label style={{ display: 'flex', alignItems: 'flex-start', gap: 10, padding: '12px 14px', border: `2px solid ${mode === 'partial' ? 'var(--accent)' : 'var(--line)'}`, borderRadius: 9, cursor: 'pointer', background: mode === 'partial' ? 'var(--accent-soft)' : 'var(--panel)' }}>
            <input type="radio" name="paymode" checked={mode === 'partial'} onChange={() => { setMode('partial'); setPayError(''); }} style={{ accentColor: 'var(--accent)', marginTop: 3 }} />
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 600, fontSize: 13.5, marginBottom: 8 }}>Pay partial amount</div>
              {mode === 'partial' && (
                <div style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                  <span style={{ fontSize: 14, fontWeight: 600 }}>$</span>
                  <input
                    type="number"
                    min="0.50"
                    max={amountDue}
                    step="0.01"
                    value={partial}
                    onChange={e => { setPartial(e.target.value); setPayError(''); }}
                    placeholder="Enter amount"
                    style={{ flex: 1, padding: '8px 10px', border: '1px solid var(--line-strong)', borderRadius: 8, fontSize: 14, fontFamily: 'var(--font-mono)', background: 'var(--panel)', outline: 'none' }}
                    onClick={e => e.stopPropagation()}
                  />
                </div>
              )}
            </div>
          </label>
        </div>

        <div style={{ background: 'var(--info-soft)', border: '1px solid rgba(29,111,184,0.2)', borderRadius: 8, padding: '8px 12px', fontSize: 12, color: 'var(--info)', marginBottom: payError ? 10 : 18 }}>
          🔒 You'll be redirected to a secure Stripe checkout page to complete payment.
        </div>

        {payError && (
          <div style={{ background: 'var(--bad-soft)', border: '1px solid rgba(180,35,24,0.2)', borderRadius: 8, padding: '8px 12px', fontSize: 12, color: 'var(--bad)', marginBottom: 18 }}>
            {payError}
          </div>
        )}

        <div style={{ display: 'flex', gap: 10 }}>
          <button onClick={onClose} disabled={loading} style={{ flex: 1, padding: '11px 0', background: 'var(--panel-2)', border: '1px solid var(--line-strong)', borderRadius: 9, fontWeight: 600, fontSize: 13.5, cursor: loading ? 'not-allowed' : 'pointer', color: 'var(--text-2)', opacity: loading ? 0.5 : 1 }}>Cancel</button>
          <button onClick={proceed} disabled={loading || (mode === 'partial' && getPayAmount() < 0.50)} style={{ flex: 2, padding: '11px 0', background: 'var(--accent)', border: 'none', borderRadius: 9, fontWeight: 700, fontSize: 13.5, cursor: (loading || (mode === 'partial' && getPayAmount() < 0.50)) ? 'not-allowed' : 'pointer', color: '#fff', opacity: (loading || (mode === 'partial' && getPayAmount() < 0.50)) ? 0.7 : 1, display: 'flex', alignItems: 'center', justifyContent: 'center', gap: 8 }}>
            {loading ? (
              <>
                <span style={{ width: 14, height: 14, border: '2px solid rgba(255,255,255,0.4)', borderTopColor: '#fff', borderRadius: '50%', display: 'inline-block', animation: 'spin 0.7s linear infinite' }} />
                Creating session…
              </>
            ) : (
              'Proceed to Payment →'
            )}
          </button>
        </div>
      </div>
    </div>
  );
}

// Payment status tone
const payTone = { unpaid: 'warn', partial: 'info', paid: 'good' };

// ── INVOICES ─────────────────────────────────────────────────
function ClientInvoices() {
  const { client, invoices, setActiveDoc } = useClient();
  const [payModal, setPayModal] = useState(null);

  const openDoc = (inv) => setActiveDoc({
    el: 'invoice', title: `Invoice ${inv.id}`, subtitle: client.name,
    file: { filename: `${inv.id}.txt`, content: `RailFlagsPro Invoice ${inv.id}\nBill to: ${client.name}\nJob: ${inv.job}\nPeriod: ${inv.period}\nHours: ${inv.hours}\nAmount: ${C_money(inv.amount)}\nDue: ${inv.due}\n`, mime: 'text/plain' },
    payload: { inv, client },
  });

  const totalPaid = invoices.filter(i => i.status === 'paid').reduce((s, i) => s + i.amount, 0);
  const totalOpen = invoices.filter(i => i.status === 'sent').reduce((s, i) => s + i.amount, 0);

  // Merge payment_status into invoice display: if DB has payment_status use it,
  // otherwise derive from invoice status
  const getPayStatus = (inv) => {
    if (inv.payment_status) return inv.payment_status;
    if (inv.status === 'paid') return 'paid';
    return 'unpaid';
  };

  return (
    <div className="anim-fade">
      <h1 style={{ margin: '0 0 4px', fontSize: 26, fontWeight: 700, letterSpacing: -0.5 }}>Invoices</h1>
      <div style={{ fontSize: 14, color: 'var(--muted)', marginBottom: 22 }}>Billing for flagging services on your jobs. {client.terms} terms.</div>
      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 14, marginBottom: 22 }}>
        <CStat label="Outstanding" value={C_money(totalOpen)} tone="warn" icon={<IconDollar size={16} />} />
        <CStat label="Paid (YTD)" value={C_money(totalPaid)} tone="good" icon={<IconCheck size={16} />} />
        <CStat label="Bill rate" value={`${C_money(client.billRate)}/hr`} sub={client.terms} icon={<IconDollar size={16} />} />
      </div>
      <CCard pad={0}>
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1.4fr 0.7fr 1fr 0.9fr 0.9fr 110px', gap: 8, padding: '11px 16px', background: 'var(--panel-2)', borderBottom: '1px solid var(--line)', fontSize: 10.5, fontWeight: 600, letterSpacing: 0.5, textTransform: 'uppercase', color: 'var(--muted)' }}>
          <span>Invoice</span><span>Job</span><span>Period</span><span style={{ textAlign: 'right' }}>Hours</span><span style={{ textAlign: 'right' }}>Amount</span><span style={{ textAlign: 'right' }}>Status</span><span style={{ textAlign: 'right' }}>Payment</span><span></span>
        </div>
        {invoices.map((inv, i) => {
          const payStatus = getPayStatus(inv);
          const canPay = inv.status !== 'draft' && payStatus !== 'paid';
          return (
            <div key={inv.id} style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1.4fr 0.7fr 1fr 0.9fr 0.9fr 110px', gap: 8, padding: '12px 16px', borderTop: i === 0 ? 'none' : '1px solid var(--line)', alignItems: 'center' }}>
              <div className="mono" style={{ fontSize: 12.5, fontWeight: 600 }}>{inv.id}</div>
              <div className="mono" style={{ fontSize: 12 }}>{inv.job}</div>
              <div style={{ fontSize: 12 }}>{inv.period}</div>
              <div className="mono" style={{ textAlign: 'right', fontSize: 12.5 }}>{C_num(inv.hours, 1)}</div>
              <div className="mono" style={{ textAlign: 'right', fontSize: 13, fontWeight: 700 }}>{C_money(inv.amount)}</div>
              <div style={{ textAlign: 'right' }}><CPill tone={statusTone[inv.status]}>{inv.status}</CPill></div>
              <div style={{ textAlign: 'right' }}><CPill tone={payTone[payStatus] || 'neutral'}>{payStatus}</CPill></div>
              <div style={{ textAlign: 'right', display: 'flex', gap: 4, justifyContent: 'flex-end' }}>
                {inv.status !== 'draft' && (
                  <button onClick={() => openDoc(inv)} style={{ background: 'var(--panel)', border: '1px solid var(--line-strong)', borderRadius: 7, padding: '5px 8px', fontSize: 11.5, fontWeight: 600, color: 'var(--text-2)', cursor: 'pointer' }}>View</button>
                )}
                {canPay && (
                  <button onClick={() => setPayModal(inv)} style={{ background: 'var(--accent)', border: 'none', borderRadius: 7, padding: '5px 8px', fontSize: 11.5, fontWeight: 700, color: '#fff', cursor: 'pointer' }}>Pay</button>
                )}
              </div>
            </div>
          );
        })}
      </CCard>

      {payModal && <PayInvoiceModal inv={payModal} onClose={() => setPayModal(null)} />}
    </div>
  );
}

// ── Invoice document template (for the doc viewer) ───────────
function InvoiceDoc({ data }) {
  const { inv, client } = data;
  return (
    <div>
      <DocHeader company="RailFlagsPro" title="Invoice" right={<><div className="rfp-doc-mono" style={{ fontSize: 14, fontWeight: 700 }}>{inv.id}</div><div style={{ fontSize: 11, color: '#555' }}>Issued {C_date(inv.issued)}</div></>} />
      <div style={{ padding: '16px 28px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 18 }}>
          <div>
            <div className="rfp-form-label">Bill to</div>
            <div style={{ fontWeight: 700, fontSize: 15 }}>{client.name}</div>
            <div style={{ fontSize: 12, color: '#555' }}>{client.railroad} · {client.terms}</div>
          </div>
          <div style={{ textAlign: 'right' }}>
            <div className="rfp-form-label">Due date</div>
            <div className="rfp-doc-mono" style={{ fontSize: 14, fontWeight: 700 }}>{C_date(inv.due)}</div>
          </div>
        </div>
        <table style={{ width: '100%', fontSize: 12, borderCollapse: 'collapse', border: '1px solid #ccc' }}>
          <thead><tr style={{ background: '#eee', borderBottom: '1.5px solid #111' }}>
            <th style={{ padding: '8px', textAlign: 'left', fontSize: 9.5, textTransform: 'uppercase' }}>Job</th>
            <th style={{ padding: '8px', textAlign: 'left', fontSize: 9.5, textTransform: 'uppercase' }}>Period</th>
            <th style={{ padding: '8px', textAlign: 'right', fontSize: 9.5, textTransform: 'uppercase' }}>Hours</th>
            <th style={{ padding: '8px', textAlign: 'right', fontSize: 9.5, textTransform: 'uppercase' }}>Rate</th>
            <th style={{ padding: '8px', textAlign: 'right', fontSize: 9.5, textTransform: 'uppercase' }}>Amount</th>
          </tr></thead>
          <tbody><tr>
            <td style={{ padding: '10px 8px' }} className="rfp-doc-mono">{inv.job}</td>
            <td style={{ padding: '10px 8px' }}>{inv.period}</td>
            <td style={{ padding: '10px 8px', textAlign: 'right' }} className="rfp-doc-mono">{C_num(inv.hours, 1)}</td>
            <td style={{ padding: '10px 8px', textAlign: 'right' }} className="rfp-doc-mono">{C_money(client.billRate)}</td>
            <td style={{ padding: '10px 8px', textAlign: 'right', fontWeight: 700 }} className="rfp-doc-mono">{C_money(inv.amount)}</td>
          </tr></tbody>
        </table>
        <div style={{ display: 'flex', justifyContent: 'flex-end', marginTop: 14 }}>
          <div style={{ width: 240 }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', padding: '6px 0', fontSize: 13 }}><span>Subtotal</span><span className="rfp-doc-mono">{C_money(inv.amount)}</span></div>
            <div style={{ display: 'flex', justifyContent: 'space-between', padding: '10px 0', borderTop: '2px solid #111', fontSize: 16, fontWeight: 700 }}><span>Total due</span><span className="rfp-doc-mono">{C_money(inv.amount)}</span></div>
          </div>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { ClientShell, ClientOverview, ClientCrews, ClientCompliance, ClientInvoices, InvoiceDoc, CCard, CPill, CStat, CTitle, PayInvoiceModal });
