const { useState, useEffect, useRef } = React;

const TOKEN_KEY = 'wnm_customer_token';
const getToken = () => localStorage.getItem(TOKEN_KEY);
const setToken = (t) => t ? localStorage.setItem(TOKEN_KEY, t) : localStorage.removeItem(TOKEN_KEY);

function api(path, opts = {}) {
  const headers = { 'Content-Type': 'application/json', ...(opts.headers || {}) };
  const token = getToken();
  if (token) headers['Authorization'] = `Bearer ${token}`;
  return fetch(path, {
    ...opts,
    headers,
    body: opts.body ? JSON.stringify(opts.body) : undefined,
  }).then(async r => {
    const j = await r.json().catch(() => ({}));
    if (!r.ok) throw j;
    return j;
  });
}

// Saniteert HTML uit de database voor gebruik in dangerouslySetInnerHTML.
// DOMPurify wordt via CDN geladen (zie customer.html). Zonder DOMPurify vallen
// we terug op volledig escapen, zodat er nooit ongesanitiseerde HTML rendert.
function sanitizeHtml(html) {
  if (html == null) return '';
  if (typeof window !== 'undefined' && window.DOMPurify) {
    return window.DOMPurify.sanitize(String(html));
  }
  return String(html)
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}

function fmtMoney(cents) {
  if (cents === null || cents === undefined) return '—';
  return '€ ' + (cents / 100).toFixed(2).replace('.', ',');
}

async function downloadPdf(path, filename) {
  const r = await fetch(path, { headers: { 'Authorization': 'Bearer ' + getToken() } });
  if (!r.ok) { alert('Download mislukt'); return; }
  const blob = await r.blob();
  const url = URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url; a.download = filename;
  document.body.appendChild(a);
  a.click();
  document.body.removeChild(a);
  URL.revokeObjectURL(url);
}
function fmtDate(s) {
  if (!s) return '—';
  const d = new Date(s.replace(' ', 'T') + (s.includes('Z') || s.includes('+') ? '' : 'Z'));
  return d.toLocaleDateString('nl-NL') + ' ' + d.toLocaleTimeString('nl-NL', { hour: '2-digit', minute: '2-digit' });
}

function useToast() {
  const [toast, setToast] = useState(null);
  const show = (msg, kind = 'success') => {
    setToast({ msg, kind });
    setTimeout(() => setToast(null), 3000);
  };
  return [toast, show];
}

function Toast({ toast }) {
  if (!toast) return null;
  return <div className={`toast toast-${toast.kind}`}>{toast.msg}</div>;
}

function Login({ onLogin }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState(null);
  const [loading, setLoading] = useState(false);
  const [forgot, setForgot] = useState(false);
  const [forgotSent, setForgotSent] = useState(false);
  const sendForgot = async (e) => {
    e.preventDefault();
    setLoading(true); setError(null);
    try {
      await api('/api/auth/customer/forgot-password', { method: 'POST', body: { email } });
      setForgotSent(true);
    } catch (err) { setError(err.error || 'Aanvraag mislukt, probeer het later opnieuw'); }
    setLoading(false);
  };
  if (forgot) return (
    <div className="login-shell">
      <form onSubmit={sendForgot} className="login-card stack">
        <h1>Wachtwoord vergeten</h1>
        {forgotSent ? (
          <p>Als <strong>{email}</strong> bij ons gekend is, krijg je binnen enkele minuten een mail met een link om een nieuw wachtwoord te kiezen. De link werkt 24 uur. Kijk ook even in je spam.</p>
        ) : (
          <>
            <p className="muted">Vul je e-mailadres in. Je krijgt een mail met een link om zelf een nieuw wachtwoord te kiezen.</p>
            <div><label>E-mail</label><input type="email" value={email} onChange={e => setEmail(e.target.value)} required autoFocus /></div>
            {error && <div style={{color: 'var(--danger)', fontSize: 13}}>{error}</div>}
            <button type="submit" className="btn-primary" disabled={loading}>{loading ? 'Bezig...' : 'Stuur me een link'}</button>
          </>
        )}
        <p className="muted small center"><a href="#" onClick={e => { e.preventDefault(); setForgot(false); setForgotSent(false); setError(null); }}>Terug naar inloggen</a></p>
      </form>
    </div>
  );
  const submit = async (e) => {
    e.preventDefault();
    setLoading(true); setError(null);
    try {
      const r = await api('/api/auth/customer/login', { method: 'POST', body: { email, password } });
      setToken(r.token);
      onLogin(r.customer);
    } catch (err) { setError(err.error || 'Login mislukt'); }
    setLoading(false);
  };
  return (
    <div className="login-shell">
      <form onSubmit={submit} className="login-card stack">
        <h1>Klantenpaneel</h1>
        <p className="muted">Welkom terug — log in om je gegevens en facturen te bekijken.</p>
        <div><label>E-mail</label><input type="email" value={email} onChange={e => setEmail(e.target.value)} required autoFocus /></div>
        <div><label>Wachtwoord</label><input type="password" value={password} onChange={e => setPassword(e.target.value)} required /></div>
        {error && <div style={{color: 'var(--danger)', fontSize: 13}}>{error}</div>}
        <button type="submit" className="btn-primary" disabled={loading}>{loading ? 'Bezig...' : 'Inloggen'}</button>
        <p className="muted small center"><a href="#" onClick={e => { e.preventDefault(); setForgot(true); setError(null); }}>Wachtwoord vergeten?</a></p>
        <p className="muted small center">Nog geen account? <a href="/#offerte">Vraag een offerte aan</a> en je account staat klaar.</p>
      </form>
    </div>
  );
}

function useDarkMode() {
  const [dark, setDark] = useState(() => {
    try { return localStorage.getItem('wnm_theme') === 'dark'; } catch { return false; }
  });
  useEffect(() => {
    document.body.classList.toggle('dark', dark);
    try { localStorage.setItem('wnm_theme', dark ? 'dark' : 'light'); } catch {}
  }, [dark]);
  return [dark, () => setDark(d => !d)];
}

function ThemeToggle({ dark, toggle }) {
  return (
    <button type="button" className="theme-toggle" onClick={toggle} title={dark ? 'Schakel naar lichte modus' : 'Schakel naar donkere modus'}>
      <span style={{ fontSize: 16 }}>{dark ? '☀️' : '🌙'}</span>
      <span>{dark ? 'Lichte modus' : 'Donkere modus'}</span>
    </button>
  );
}

function Sidebar({ active, setActive, customer, onLogout, unreadCount, dark, toggleDark }) {
  const items = [
    { id: 'dashboard', label: 'Dashboard' },
    { id: 'announcements', label: '📢 Mededelingen', badge: unreadCount },
    { id: 'credentials', label: '🔐 Logingegevens' },
    { id: 'info', label: 'Info & uitleg' },
    { id: 'quotes', label: 'Mijn offertes' },
    { id: 'orders', label: 'Mijn bestellingen' },
    { id: 'invoices', label: 'Mijn facturen' },
    { id: 'licenses', label: '🔑 Licenties' },
    { id: 'tickets', label: 'Support tickets' },
    { id: 'account', label: 'Mijn gegevens' },
  ];
  const external = [
    { label: '✉️ Webmail', href: 'https://webmail.webhosting.be/' },
  ];
  return (
    <aside className="sidebar">
      <div className="brand">WNM-Host</div>
      <nav>
        {items.map(i => (
          <a key={i.id} className={active === i.id ? 'active' : ''} onClick={(e) => { e.preventDefault(); setActive(i.id); }} href="#">
            <span>{i.label}</span>
            {i.badge > 0 && (
              <span style={{ background: '#ef4444', color: '#fff', borderRadius: 10, padding: '1px 8px', fontSize: 11, fontWeight: 700, marginLeft: 8 }}>{i.badge}</span>
            )}
          </a>
        ))}
        {external.length > 0 && (
          <div style={{marginTop: 12, paddingTop: 12, borderTop: '1px solid rgba(255,255,255,0.1)'}}>
            {external.map(e => (
              <a key={e.href} href={e.href} target="_blank" rel="noopener noreferrer" title="Opent in nieuw tabblad">
                {e.label} ↗
              </a>
            ))}
          </div>
        )}
      </nav>
      <ThemeToggle dark={dark} toggle={toggleDark} />
      <div className="user-info">
        <strong>{customer.name}</strong>
        <span>{customer.email}</span>
        {customer.company && <span style={{display: 'block', marginTop: 4}}>{customer.company}</span>}
        <a className="logout" onClick={onLogout}>Uitloggen</a>
      </div>
    </aside>
  );
}

const PROFILE_FIELDS = [
  { key: 'name', label: 'Naam' },
  { key: 'email', label: 'E-mailadres' },
  { key: 'company', label: 'Bedrijf', optional: true },
  { key: 'phone', label: 'Telefoonnummer' },
  { key: 'address', label: 'Adres' },
  { key: 'postal_code', label: 'Postcode' },
  { key: 'city', label: 'Stad' },
  { key: 'country', label: 'Land' },
  { key: 'vat_number', label: 'BTW nummer', optional: true },
];

function profileCompletion(me) {
  if (!me) return { percent: 0, missing: [], total: 0, filled: 0 };
  const required = PROFILE_FIELDS.filter(f => !f.optional);
  const filled = required.filter(f => me[f.key] && String(me[f.key]).trim() !== '');
  const percent = required.length === 0 ? 100 : Math.round(100 * filled.length / required.length);
  const missing = required.filter(f => !me[f.key] || String(me[f.key]).trim() === '');
  return { percent, missing, total: required.length, filled: filled.length };
}

function ProfileCompletionBanner({ setActive }) {
  const [me, setMe] = useState(null);
  useEffect(() => { api('/api/customer/me').then(setMe); }, []);
  if (!me) return null;
  const { percent, missing } = profileCompletion(me);
  if (percent === 100) return null;

  return (
    <div className="card mb-2" style={{
      background: percent < 50 ? '#fef3c7' : '#dbeafe',
      borderColor: percent < 50 ? '#f59e0b' : 'var(--primary)',
      borderLeft: `4px solid ${percent < 50 ? '#f59e0b' : 'var(--primary)'}`,
    }}>
      <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, flexWrap: 'wrap'}}>
        <div style={{flex: 1, minWidth: 240}}>
          <strong style={{fontSize: 15}}>
            📋 Vul je gegevens aan voor correcte facturen
          </strong>
          <div className="muted small mt-1">
            Je profiel is voor <strong>{percent}%</strong> volledig.
            Nog in te vullen: {missing.slice(0, 3).map(f => f.label).join(', ')}
            {missing.length > 3 && ` en ${missing.length - 3} meer`}.
          </div>
          <div style={{background: '#e5e7eb', borderRadius: 4, height: 8, overflow: 'hidden', marginTop: 8, maxWidth: 400}}>
            <div style={{background: percent < 50 ? '#f59e0b' : 'var(--primary)', height: '100%', width: `${percent}%`, transition: 'width .3s'}}></div>
          </div>
        </div>
        <button className="btn-primary" onClick={() => setActive('account')}>Gegevens aanvullen →</button>
      </div>
    </div>
  );
}

function Dashboard({ customer, setActive }) {
  const [data, setData] = useState(null);
  useEffect(() => { api('/api/customer/dashboard').then(setData); }, []);
  if (!data) return <div className="muted">Laden...</div>;

  return (
    <div>
      <div className="page-header"><h1>Welkom terug, {customer.name}</h1></div>
      <ProfileCompletionBanner setActive={setActive} />
      <div className="grid grid-4 mb-2">
        <div className="stat-card" style={{cursor: 'pointer'}} onClick={() => setActive('quotes')}>
          <div className="stat-label">Open offertes</div>
          <div className="stat-value">{data.stats.open_quotes}</div>
        </div>
        <div className="stat-card" style={{cursor: 'pointer'}} onClick={() => setActive('orders')}>
          <div className="stat-label">Actieve bestellingen</div>
          <div className="stat-value">{data.stats.active_orders}</div>
        </div>
        <div className="stat-card" style={{cursor: 'pointer'}} onClick={() => setActive('invoices')}>
          <div className="stat-label">Open facturen</div>
          <div className="stat-value">{data.stats.open_invoices}</div>
        </div>
        <div className="stat-card" style={{cursor: 'pointer'}} onClick={() => setActive('tickets')}>
          <div className="stat-label">Open tickets</div>
          <div className="stat-value">{data.stats.open_tickets}</div>
        </div>
      </div>
      <div className="grid grid-2">
        <div className="card">
          <h3 className="mt-0">Recente facturen</h3>
          <table>
            <tbody>
              {data.recent_invoices.map(i => (
                <tr key={i.id}>
                  <td><strong>{i.invoice_number}</strong><br/><small className="muted">{i.description}</small></td>
                  <td><span className={`badge badge-${i.status}`}>{i.status}</span></td>
                  <td className="right">{fmtMoney(i.total_cents)}</td>
                </tr>
              ))}
              {data.recent_invoices.length === 0 && <tr><td className="muted center" colSpan="3">Nog geen facturen</td></tr>}
            </tbody>
          </table>
        </div>
        <div className="card">
          <h3 className="mt-0">Recente tickets</h3>
          <table>
            <tbody>
              {data.recent_tickets.map(t => (
                <tr key={t.id}>
                  <td><strong>{t.reference}</strong><br/><small className="muted">{t.subject}</small></td>
                  <td><span className={`badge badge-${t.status}`}>{t.status}</span></td>
                </tr>
              ))}
              {data.recent_tickets.length === 0 && <tr><td className="muted center" colSpan="2">Nog geen tickets</td></tr>}
            </tbody>
          </table>
        </div>
      </div>
    </div>
  );
}

const DETAIL_LABELS = {
  business_type: 'Soort bedrijf / branche',
  business_description: 'Beschrijving van het bedrijf',
  target_audience: 'Doelgroep',
  current_website: 'Huidige website',
  has_logo: 'Logo aanwezig',
  content_provider: 'Wie levert content',
  has_domain: 'Domein aanwezig',
  needs_hosting: 'Hosting nodig',
  seo_important: 'SEO belang',
  maintenance: 'Maandelijks onderhoud',
  installation: 'Installatie / livegang',
  pages: 'Gewenste pagina\'s',
  other_pages: 'Andere pagina\'s',
  features: 'Functionaliteiten',
  other_features: 'Andere functies',
  style: 'Designstijl',
  color_preferences: 'Kleurvoorkeuren',
  inspiration_urls: 'Inspiratie URLs',
  webshop_products_count: 'Aantal producten (webshop)',
  webshop_payment_methods: 'Betaalmethoden (webshop)',
  hosting_site_type: 'Type website',
  hosting_traffic: 'Verwacht bezoek/maand',
  hosting_mailboxes: 'Aantal mailboxen',
  hosting_migration: 'Migratie',
  vps_purpose: 'VPS doel',
  vps_managed: 'Beheerd of zelf',
  vps_os: 'OS voorkeur',
  domain_name: 'Domeinnaam',
  domain_transfer: 'Type registratie',
};

const DETAIL_VALUE_LABELS = {
  has_logo: { yes: 'Ja, in goede kwaliteit', rough: 'Ja maar vernieuwen', no: 'Nee, laten maken' },
  content_provider: { self: 'Ik lever alles', combi: 'Combinatie', wnm: 'WNM-Host doet alles' },
  has_domain: { yes: 'Ja', needs_register: 'Nee, nieuw registreren', undecided: 'Nog niet bepaald' },
  needs_hosting: { yes: 'Ja, bij WNM-Host', have: 'Heb al hosting', undecided: 'Nog niet bepaald' },
  seo_important: { critical: 'Zeer belangrijk', important: 'Belangrijk', nice: 'Mooi meegenomen', no: 'Niet relevant' },
  maintenance: { wnm: 'WNM-Host verzorgt maandelijks', self: 'Ik doe zelf', ondemand: 'Alleen op aanvraag', undecided: 'Nog niet bepaald' },
  installation: { wnm: 'WNM-Host installeert + zet live', self: 'Ik installeer zelf', undecided: 'Nog niet bepaald' },
  hosting_traffic: { '<1k': '< 1.000', '1k-10k': '1k–10k', '10k-50k': '10k–50k', '50k+': '50k+', unknown: 'Onbekend' },
  hosting_migration: { yes: 'Ja, hulp gewenst', no: 'Nee, nieuwe site', self: 'Doe ik zelf' },
  vps_managed: { managed: 'Volledig beheerd', self: 'Zelfbeheerd', hybrid: 'Combi' },
  domain_transfer: { new: 'Nieuwe registratie', transfer: 'Verhuizing', check: 'Eerst checken' },
};

function QuoteDetailsView({ quote }) {
  let details = null;
  try { details = quote.details_json ? JSON.parse(quote.details_json) : null; } catch {}
  const hasExtras = quote.budget_range || quote.deadline || details;
  if (!hasExtras) return null;
  const renderVal = (k, v) => {
    if (v === null || v === undefined || v === '') return null;
    if (Array.isArray(v)) return v.length ? v.join(', ') : null;
    const labels = DETAIL_VALUE_LABELS[k];
    if (labels && labels[v]) return labels[v];
    return String(v);
  };
  return (
    <div className="card" style={{background: '#f8fafc', marginTop: 12}}>
      <h3 className="mt-0">Wat je hebt ingevuld bij de aanvraag</h3>
      {(quote.budget_range || quote.deadline) && (
        <div className="grid grid-2" style={{marginBottom: 12}}>
          {quote.budget_range && <div><strong>Budget:</strong> {quote.budget_range}</div>}
          {quote.deadline && <div><strong>Gewenste deadline:</strong> {quote.deadline}</div>}
        </div>
      )}
      {details && (
        <table style={{margin: 0}}>
          <tbody>
            {Object.entries(details).map(([k, v]) => {
              const rendered = renderVal(k, v);
              if (rendered === null) return null;
              return (
                <tr key={k}>
                  <td style={{verticalAlign: 'top', width: 180, color: 'var(--muted)', fontSize: 13, fontWeight: 500}}>{DETAIL_LABELS[k] || k}</td>
                  <td style={{whiteSpace: 'pre-wrap'}}>{rendered}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      )}
    </div>
  );
}

function SignatureModal({ quote, customerName, mode, onClose, onSubmit, busy }) {
  // mode: 'sign' = enkel ondertekenen, 'sign-and-accept' = onderteken + accepteer in 1 actie
  const [name, setName] = useState(customerName || '');
  const [method, setMethod] = useState('draw'); // draw | type
  const [hasDrawing, setHasDrawing] = useState(false);
  const canvasRef = useRef(null);
  const ctxRef = useRef(null);
  const drawingRef = useRef(false);

  // Canvas opzetten
  useEffect(() => {
    const c = canvasRef.current;
    if (!c) return;
    const dpr = window.devicePixelRatio || 1;
    const rect = c.getBoundingClientRect();
    c.width = Math.floor(rect.width * dpr);
    c.height = Math.floor(rect.height * dpr);
    const ctx = c.getContext('2d');
    ctx.scale(dpr, dpr);
    ctx.lineWidth = 2.2;
    ctx.lineCap = 'round';
    ctx.lineJoin = 'round';
    ctx.strokeStyle = '#0a2540';
    ctxRef.current = ctx;
  }, [method]);

  const getPos = (e) => {
    const c = canvasRef.current;
    const rect = c.getBoundingClientRect();
    const t = e.touches ? e.touches[0] : e;
    return { x: t.clientX - rect.left, y: t.clientY - rect.top };
  };
  const start = (e) => {
    e.preventDefault();
    drawingRef.current = true;
    const p = getPos(e);
    ctxRef.current.beginPath();
    ctxRef.current.moveTo(p.x, p.y);
  };
  const move = (e) => {
    if (!drawingRef.current) return;
    e.preventDefault();
    const p = getPos(e);
    ctxRef.current.lineTo(p.x, p.y);
    ctxRef.current.stroke();
    if (!hasDrawing) setHasDrawing(true);
  };
  const end = () => { drawingRef.current = false; };
  const clearCanvas = () => {
    const c = canvasRef.current;
    if (c) ctxRef.current.clearRect(0, 0, c.width, c.height);
    setHasDrawing(false);
  };

  const submit = () => {
    if (!name.trim()) { alert('Vul je volledige naam in.'); return; }
    if (method === 'draw' && !hasDrawing) { alert('Plaats eerst je handtekening in het vak.'); return; }
    const payload = {
      signature_name: name.trim(),
      signature_method: method,
      signature_data: method === 'draw' ? canvasRef.current.toDataURL('image/png') : null,
    };
    onSubmit(payload);
  };

  return (
    <div className="modal-backdrop" onClick={() => { if (!busy) onClose(); }}>
      <div className="modal" onClick={e => e.stopPropagation()} style={{ maxWidth: 620 }}>
        <h2>{mode === 'sign-and-accept' ? 'Offerte ondertekenen & accepteren' : 'Offerte ondertekenen'}</h2>
        <p className="muted">Offerte <strong>{quote.reference}</strong> — {quote.title}</p>

        <label style={{ marginTop: 12 }}>Je volledige naam (wettelijke ondertekenaar)</label>
        <input type="text" value={name} onChange={e => setName(e.target.value)} placeholder="Voornaam Achternaam" />

        <div style={{ marginTop: 16, display: 'flex', gap: 12 }}>
          <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontWeight: 'normal' }}>
            <input type="radio" name="sigm" value="draw" checked={method === 'draw'} onChange={() => setMethod('draw')} /> ✍️ Handgeschreven
          </label>
          <label style={{ display: 'flex', alignItems: 'center', gap: 6, fontWeight: 'normal' }}>
            <input type="radio" name="sigm" value="type" checked={method === 'type'} onChange={() => setMethod('type')} /> ⌨️ Getypte naam
          </label>
        </div>

        {method === 'draw' && (
          <div style={{ marginTop: 8 }}>
            <div style={{ border: '2px dashed #cbd5e1', borderRadius: 8, background: '#fff', position: 'relative' }}>
              <canvas
                ref={canvasRef}
                style={{ width: '100%', height: 180, display: 'block', touchAction: 'none', cursor: 'crosshair' }}
                onMouseDown={start} onMouseMove={move} onMouseUp={end} onMouseLeave={end}
                onTouchStart={start} onTouchMove={move} onTouchEnd={end}
              />
              {!hasDrawing && <div style={{ position: 'absolute', top: '50%', left: '50%', transform: 'translate(-50%, -50%)', color: '#94a3b8', pointerEvents: 'none', fontStyle: 'italic' }}>Teken hier je handtekening</div>}
            </div>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 6 }}>
              <p className="muted small" style={{ margin: 0 }}>Sleep met de muis of vinger om je handtekening te plaatsen.</p>
              <button className="btn-sm" type="button" onClick={clearCanvas}>Wissen</button>
            </div>
          </div>
        )}

        {method === 'type' && (
          <div style={{ marginTop: 8, padding: 16, background: '#f9fafb', borderRadius: 8, textAlign: 'center' }}>
            <span style={{ fontFamily: 'cursive', fontSize: 32, color: '#0a2540' }}>{name || 'Je naam'}</span>
            <p className="muted small" style={{ marginTop: 8 }}>Je naam dient als digitale ondertekening.</p>
          </div>
        )}

        <div className="card" style={{ marginTop: 12, background: '#fffbeb', borderLeft: '3px solid #f59e0b', padding: 10, fontSize: 13 }}>
          <strong>📝 Juridisch:</strong> door op {mode === 'sign-and-accept' ? '“Ondertekenen & accepteren”' : '“Ondertekenen”'} te klikken, verklaar je akkoord te zijn met de inhoud van deze offerte en bevestig je dat je bevoegd bent te ondertekenen namens je organisatie. Je IP-adres en tijdstip worden vastgelegd voor onze administratie.
        </div>

        <div style={{ display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 16 }}>
          <button type="button" onClick={onClose} disabled={busy}>Annuleren</button>
          <button type="button" className="btn-primary" onClick={submit} disabled={busy}>
            {busy ? 'Bezig…' : (mode === 'sign-and-accept' ? '✓ Ondertekenen & accepteren' : '✍️ Ondertekenen')}
          </button>
        </div>
      </div>
    </div>
  );
}

function Quotes({ showToast, setActive }) {
  const [quotes, setQuotes] = useState([]);
  const [view, setView] = useState(null);
  const [accepting, setAccepting] = useState(null);
  const [signFor, setSignFor] = useState(null); // {quote, mode}
  const [customer, setCustomer] = useState(null);
  useEffect(() => { api('/api/customer/me').then(setCustomer).catch(() => {}); }, []);
  const load = () => api('/api/customer/quotes').then(setQuotes);
  useEffect(() => { load(); }, []);

  const statusLabel = (s) => ({
    new: 'In behandeling', priced: 'Klaar om te accepteren',
    accepted: 'Geaccepteerd — factuur staat klaar', paid: 'Betaald',
  }[s] || s);

  // Klant kiest "Accepteren" → open eerst de handtekening-modal; daarna roept submit
  // /accept aan mét handtekening, in één call.
  const openAccept = (q) => setSignFor({ quote: q, mode: 'sign-and-accept' });
  // Voor reeds geaccepteerde, maar nog niet ondertekende offertes
  const openSign = (q) => setSignFor({ quote: q, mode: 'sign' });

  const submitSign = async (payload) => {
    const { quote, mode } = signFor;
    setAccepting(quote.id);
    try {
      if (mode === 'sign-and-accept') {
        const r = await api(`/api/customer/quotes/${quote.id}/accept`, { method: 'POST', body: payload });
        if (r.ok) {
          showToast('Offerte ondertekend & geaccepteerd! De factuur staat klaar bij "Mijn facturen".');
          setSignFor(null); setView(null); load();
          if (setActive) setTimeout(() => setActive('invoices'), 800);
        } else { showToast('Fout: ' + (r.error || 'onbekend'), 'error'); }
      } else {
        const r = await api(`/api/customer/quotes/${quote.id}/sign`, { method: 'POST', body: payload });
        if (r.ok) { showToast('Offerte ondertekend.'); setSignFor(null); setView(null); load(); }
        else { showToast('Fout: ' + (r.error || 'onbekend'), 'error'); }
      }
    } catch (e) {
      showToast('Fout: ' + (e.error || e.message || ''), 'error');
    } finally {
      setAccepting(null);
    }
  };

  return (
    <div>
      <div className="page-header"><h1>Mijn offertes</h1></div>
      <div className="card" style={{padding: 0}}>
        <table>
          <thead><tr><th>Ref</th><th>Titel</th><th>Type</th><th>Status</th><th>Bedrag</th><th>Datum</th><th></th></tr></thead>
          <tbody>
            {quotes.map(q => (
              <tr key={q.id}>
                <td><strong>{q.reference}</strong></td>
                <td>{q.title}</td>
                <td>{q.type}</td>
                <td><span className={`badge badge-${q.status}`}>{statusLabel(q.status)}</span></td>
                <td>{fmtMoney(q.amount_cents)}</td>
                <td>{fmtDate(q.created_at)}</td>
                <td style={{display: 'flex', gap: 4, flexWrap: 'wrap'}}>
                  {q.has_uploaded_pdf && (
                    <button className="btn-sm" style={{background: '#0a2540', color: '#fff'}} onClick={() => downloadPdf(`/api/customer/quotes/${q.id}/uploaded-pdf`, q.uploaded_pdf_filename || `${q.reference}.pdf`)} title="Bekijk de offerte">📄 Offerte</button>
                  )}
                  {q.signed_at && <span className="badge badge-paid" title={`Ondertekend door ${q.signature_name || ''}`}>✍️ Ondertekend</span>}
                  {q.status === 'priced' && (
                    <button className="btn btn-primary btn-sm" disabled={accepting === q.id} onClick={() => openAccept(q)}>
                      {accepting === q.id ? 'Bezig...' : '✍️ Onderteken & accepteer'}
                    </button>
                  )}
                  {q.status === 'accepted' && !q.signed_at && (
                    <button className="btn btn-primary btn-sm" disabled={accepting === q.id} onClick={() => openSign(q)}>
                      ✍️ Onderteken
                    </button>
                  )}
                  {q.status === 'accepted' && setActive && (
                    <button className="btn-sm" onClick={() => setActive('invoices')}>Naar factuur →</button>
                  )}
                  <button className="btn-sm" onClick={() => setView(q)}>Bekijken</button>
                </td>
              </tr>
            ))}
            {quotes.length === 0 && <tr><td colSpan="7" className="muted center" style={{padding: 40}}>Nog geen offertes</td></tr>}
          </tbody>
        </table>
      </div>
      {view && (
        <div className="modal-backdrop" onClick={() => setView(null)}>
          <div className="modal" onClick={e => e.stopPropagation()} style={{maxWidth: 820}}>
            <h2>Offerte {view.reference}</h2>
            <p><strong>{view.title}</strong></p>
            <p className="muted">Aangevraagd op {fmtDate(view.created_at)}</p>
            <p><strong>Status:</strong> <span className={`badge badge-${view.status}`}>{statusLabel(view.status)}</span></p>
            <p><strong>Bedrag:</strong> {fmtMoney(view.amount_cents)}</p>
            {view.description && <><p><strong>Omschrijving:</strong></p><p style={{whiteSpace: 'pre-wrap'}}>{view.description}</p></>}
            <QuoteDetailsView quote={view} />
            {view.has_uploaded_pdf && (
              <div className="card mt-2" style={{background: '#f0f9ff', borderLeft: '3px solid #1f6feb'}}>
                📄 <strong>Offerte-document beschikbaar</strong> — bekijk de details voor je accepteert.
                <div className="mt-1"><button className="btn-sm" style={{background: '#0a2540', color: '#fff'}} onClick={() => downloadPdf(`/api/customer/quotes/${view.id}/uploaded-pdf`, view.uploaded_pdf_filename || `${view.reference}.pdf`)}>📄 Offerte bekijken</button></div>
              </div>
            )}
            {view.signed_at && (
              <div className="card mt-2" style={{background: '#eef2ff', borderLeft: '3px solid #6366f1'}}>
                ✍️ <strong>Ondertekend</strong> door <em>{view.signature_name}</em> op {fmtDate(view.signed_at)} ({view.signature_method === 'draw' ? 'handgeschreven' : 'getypte naam'}).
              </div>
            )}
            {view.status === 'priced' && (
              <button className="btn btn-primary mt-2" disabled={accepting === view.id} onClick={() => openAccept(view)}>
                {accepting === view.id ? 'Bezig...' : '✍️ Onderteken & accepteer offerte'}
              </button>
            )}
            {view.status === 'accepted' && !view.signed_at && (
              <button className="btn btn-primary mt-2" disabled={accepting === view.id} onClick={() => openSign(view)}>
                ✍️ Offerte ondertekenen
              </button>
            )}
            {view.status === 'accepted' && (
              <div className="card mt-2" style={{background: '#ecfdf5', borderLeft: '3px solid #10b981'}}>
                ✓ Geaccepteerd — de factuur staat klaar bij <strong>Mijn facturen</strong> om te betalen.
              </div>
            )}
            <div style={{textAlign: 'right', marginTop: 16}}><button onClick={() => setView(null)}>Sluiten</button></div>
          </div>
        </div>
      )}
      {signFor && (
        <SignatureModal
          quote={signFor.quote}
          mode={signFor.mode}
          customerName={customer?.name}
          busy={accepting === signFor.quote.id}
          onClose={() => setSignFor(null)}
          onSubmit={submitSign}
        />
      )}
    </div>
  );
}

function Orders() {
  const [orders, setOrders] = useState([]);
  const [view, setView] = useState(null);
  useEffect(() => { api('/api/customer/orders').then(setOrders); }, []);
  return (
    <div>
      <div className="page-header"><h1>Mijn bestellingen</h1></div>
      <div className="card" style={{padding: 0}}>
        <table>
          <thead><tr><th>Ref</th><th>Product</th><th>Status</th><th>Bedrag</th><th>Volgende verlenging</th><th>Datum</th><th></th></tr></thead>
          <tbody>
            {orders.map(o => (
              <tr key={o.id}>
                <td><strong>{o.reference}</strong></td>
                <td>{o.product_name}</td>
                <td><span className={`badge badge-${o.status}`}>{o.status}</span></td>
                <td>{fmtMoney(o.amount_cents)}</td>
                <td>{o.next_renewal_at || '—'}</td>
                <td>{fmtDate(o.created_at)}</td>
                <td><button className="btn-sm" onClick={() => setView(o)}>Details</button></td>
              </tr>
            ))}
            {orders.length === 0 && <tr><td colSpan="7" className="muted center" style={{padding: 40}}>Nog geen bestellingen</td></tr>}
          </tbody>
        </table>
      </div>
      {view && <OrderDetailModal order={view} onClose={() => setView(null)} />}
    </div>
  );
}

function OrderDetailModal({ order, onClose }) {
  const milestones = order.milestones || [];
  const completed = milestones.filter(m => m.status === 'completed').length;
  const progress = milestones.length ? Math.round(100 * completed / milestones.length) : null;

  return (
    <div className="modal-backdrop">
      <div className="modal" onClick={e => e.stopPropagation()} style={{maxWidth: 720}}>
        <h2>Bestelling {order.reference}</h2>
        <p><strong>{order.product_name}</strong> ({order.category})</p>
        <p><strong>Status:</strong> <span className={`badge badge-${order.status}`}>{order.status}</span></p>
        <p><strong>Bedrag:</strong> {fmtMoney(order.amount_cents)} ({order.billing_cycle})</p>
        {order.mollie_subscription_id && <p className="muted small">Automatische verlenging actief</p>}
        <p><strong>Volgende verlenging:</strong> {order.next_renewal_at || '—'}</p>

        {milestones.length > 0 && (
          <div className="card mt-2">
            <h4 className="mt-0">Project voortgang ({progress}% klaar)</h4>
            <div style={{background: '#e5e7eb', borderRadius: 4, height: 10, overflow: 'hidden', marginBottom: 16}}>
              <div style={{background: 'var(--primary)', height: '100%', width: `${progress}%`, transition: 'width .3s'}}></div>
            </div>
            <div className="stack">
              {milestones.map(m => (
                <div key={m.id} style={{display: 'flex', gap: 12, alignItems: 'flex-start'}}>
                  <div style={{
                    width: 28, height: 28, borderRadius: '50%', flexShrink: 0,
                    background: m.status === 'completed' ? 'var(--success)' : m.status === 'in_progress' ? 'var(--warning)' : '#e5e7eb',
                    color: '#fff', display: 'flex', alignItems: 'center', justifyContent: 'center', fontWeight: 'bold'
                  }}>{m.status === 'completed' ? '✓' : m.status === 'in_progress' ? '◐' : '○'}</div>
                  <div>
                    <strong>{m.title}</strong>
                    {m.description && <div className="muted small">{m.description}</div>}
                    {m.completed_at && <div className="muted small">Afgerond op {fmtDate(m.completed_at)}</div>}
                  </div>
                </div>
              ))}
            </div>
          </div>
        )}

        {order.provisioning_details && (
          <div className="card" style={{background: '#f8fafc', marginTop: 16}}>
            <h4 className="mt-0">Login / toegangsgegevens</h4>
            <pre style={{whiteSpace: 'pre-wrap', fontFamily: 'monospace', fontSize: 13, margin: 0}}>{order.provisioning_details}</pre>
          </div>
        )}
        <div style={{textAlign: 'right', marginTop: 16}}><button onClick={onClose}>Sluiten</button></div>
      </div>
    </div>
  );
}

function Invoices() {
  const [invoices, setInvoices] = useState([]);
  const [view, setView] = useState(null);
  useEffect(() => { api('/api/customer/invoices').then(setInvoices); }, []);
  return (
    <div>
      <div className="page-header"><h1>Mijn facturen</h1></div>
      <div className="card" style={{padding: 0}}>
        <table>
          <thead><tr><th>Nummer</th><th>Omschrijving</th><th>Status</th><th>Bedrag</th><th>Datum</th><th></th></tr></thead>
          <tbody>
            {invoices.map(i => (
              <tr key={i.id}>
                <td><strong>{i.invoice_number}</strong></td>
                <td>{i.description}</td>
                <td><span className={`badge badge-${i.status}`}>{i.status === 'paid' ? 'Betaald' : i.status === 'open' ? 'Open' : i.status}</span></td>
                <td>
                  {fmtMoney(i.total_cents + (i.surcharge_cents || 0))}
                  {i.surcharge_cents > 0 && <><br/><small className="muted" style={{color: '#b91c1c'}}>incl. {fmtMoney(i.surcharge_cents)} toeslag</small></>}
                </td>
                <td>{fmtDate(i.created_at)}</td>
                <td style={{display: 'flex', gap: 4, flexWrap: 'wrap'}}>
                  {i.status === 'open' && i.mollie_payment_url && <a href={i.mollie_payment_url} className="btn btn-primary btn-sm">Betalen</a>}
                  {i.has_uploaded_pdf && (
                    <button
                      className="btn-sm"
                      style={{background: '#0a2540', color: '#fff'}}
                      onClick={() => downloadPdf(`/api/customer/invoices/${i.id}/uploaded-pdf`, i.uploaded_pdf_filename || `${i.invoice_number}.pdf`)}
                      title="Officiële factuur"
                    >📄 Factuur</button>
                  )}
                  <button
                    className="btn-sm"
                    onClick={() => downloadPdf(`/api/customer/invoices/${i.id}/pdf`, `${i.invoice_number}-betaalbewijs.pdf`)}
                    title="Betaalbewijs / overzicht"
                  >Betaalbewijs</button>
                  <button className="btn-sm" onClick={() => setView(i)}>Details</button>
                </td>
              </tr>
            ))}
            {invoices.length === 0 && <tr><td colSpan="6" className="muted center" style={{padding: 40}}>Nog geen facturen</td></tr>}
          </tbody>
        </table>
      </div>
      {view && (
        <div className="modal-backdrop" onClick={() => setView(null)}>
          <div className="modal" onClick={e => e.stopPropagation()}>
            <h2>Factuur {view.invoice_number}</h2>
            <p><strong>{view.description}</strong></p>
            <p className="muted">Aangemaakt op {fmtDate(view.created_at)}</p>
            <table style={{margin: '16px 0'}}>
              <tbody>
                <tr><td>Subtotaal</td><td className="right">{fmtMoney(view.amount_cents)}</td></tr>
                <tr><td>BTW</td><td className="right">{fmtMoney(view.vat_cents)}</td></tr>
                {view.surcharge_cents > 0 && <tr style={{color: '#b91c1c'}}><td>Toeslag laattijdige betaling</td><td className="right">{fmtMoney(view.surcharge_cents)}</td></tr>}
                <tr style={{fontWeight: 'bold', fontSize: 16}}><td>Totaal</td><td className="right">{fmtMoney(view.total_cents + (view.surcharge_cents || 0))}</td></tr>
              </tbody>
            </table>
            <p><strong>Status:</strong> <span className={`badge badge-${view.status}`}>{view.status}</span></p>
            {view.paid_at && <p><strong>Betaald op:</strong> {fmtDate(view.paid_at)}</p>}
            {view.status === 'open' && view.mollie_payment_url && (
              <a href={view.mollie_payment_url} className="btn btn-primary">Betaal nu via Mollie</a>
            )}
            <div style={{textAlign: 'right', marginTop: 16}}><button onClick={() => setView(null)}>Sluiten</button></div>
          </div>
        </div>
      )}
    </div>
  );
}

function Tickets({ showToast }) {
  const [tickets, setTickets] = useState([]);
  const [view, setView] = useState(null);
  const [showNew, setShowNew] = useState(false);
  const load = () => api('/api/customer/tickets').then(setTickets);
  useEffect(() => { load(); }, []);

  const openTicket = (id) => api(`/api/customer/tickets/${id}`).then(setView);

  return (
    <div>
      <div className="page-header">
        <h1>Support tickets</h1>
        <button className="btn-primary" onClick={() => setShowNew(true)}>+ Nieuw ticket</button>
      </div>
      <div className="card" style={{padding: 0}}>
        <table>
          <thead><tr><th>Ref</th><th>Onderwerp</th><th>Status</th><th>Prioriteit</th><th>Berichten</th><th>Bijgewerkt</th></tr></thead>
          <tbody>
            {tickets.map(t => (
              <tr key={t.id} style={{cursor: 'pointer'}} onClick={() => openTicket(t.id)}>
                <td><strong>{t.reference}</strong></td>
                <td>{t.subject}</td>
                <td><span className={`badge badge-${t.status}`}>{t.status === 'open' ? 'Open' : t.status === 'waiting_customer' ? 'Antwoord nodig' : t.status === 'resolved' ? 'Opgelost' : t.status}</span></td>
                <td><span className={`badge badge-${t.priority}`}>{t.priority}</span></td>
                <td>{t.message_count}</td>
                <td>{fmtDate(t.updated_at)}</td>
              </tr>
            ))}
            {tickets.length === 0 && <tr><td colSpan="6" className="muted center" style={{padding: 40}}>Nog geen tickets. Klik op "+ Nieuw ticket" om een vraag te stellen.</td></tr>}
          </tbody>
        </table>
      </div>
      {showNew && <NewTicketModal onClose={() => setShowNew(false)} onSaved={() => { setShowNew(false); load(); showToast('Ticket aangemaakt'); }} />}
      {view && <TicketView data={view} onClose={() => setView(null)} onReply={() => openTicket(view.ticket.id).then(() => load())} showToast={showToast} />}
    </div>
  );
}

function NewTicketModal({ onClose, onSaved }) {
  const [form, setForm] = useState({ subject: '', message: '', priority: 'normal', category: 'algemeen' });
  const [loading, setLoading] = useState(false);
  const submit = async (e) => {
    e.preventDefault();
    setLoading(true);
    await api('/api/customer/tickets', { method: 'POST', body: form });
    onSaved();
  };
  return (
    <div className="modal-backdrop">
      <div className="modal" onClick={e => e.stopPropagation()}>
        <h2>Nieuw support ticket</h2>
        <form onSubmit={submit} className="stack">
          <div><label>Onderwerp *</label><input value={form.subject} onChange={e => setForm({...form, subject: e.target.value})} required /></div>
          <div className="row">
            <div className="col"><label>Categorie</label>
              <select value={form.category} onChange={e => setForm({...form, category: e.target.value})}>
                <option value="algemeen">Algemene vraag</option>
                <option value="hosting">Hosting probleem</option>
                <option value="design">Webdesign / project</option>
                <option value="facturatie">Facturatie</option>
                <option value="domein">Domein</option>
              </select>
            </div>
            <div className="col"><label>Prioriteit</label>
              <select value={form.priority} onChange={e => setForm({...form, priority: e.target.value})}>
                <option value="low">Laag</option>
                <option value="normal">Normaal</option>
                <option value="high">Hoog (urgent probleem)</option>
              </select>
            </div>
          </div>
          <div><label>Je vraag / probleem *</label><textarea rows="6" value={form.message} onChange={e => setForm({...form, message: e.target.value})} required /></div>
          <div style={{display: 'flex', justifyContent: 'flex-end', gap: 8}}>
            <button type="button" onClick={onClose}>Annuleren</button>
            <button type="submit" className="btn-primary" disabled={loading}>Versturen</button>
          </div>
        </form>
      </div>
    </div>
  );
}

function TicketView({ data, onClose, onReply, showToast }) {
  const { ticket, messages } = data;
  const [reply, setReply] = useState('');
  const [loading, setLoading] = useState(false);

  const send = async () => {
    if (!reply.trim()) return;
    setLoading(true);
    await api(`/api/customer/tickets/${ticket.id}/messages`, { method: 'POST', body: { message: reply } });
    setReply('');
    showToast('Bericht verstuurd');
    onReply();
    setLoading(false);
  };

  return (
    <div className="modal-backdrop">
      <div className="modal" onClick={e => e.stopPropagation()} style={{maxWidth: 720}}>
        <h2>Ticket {ticket.reference}</h2>
        <p><strong>{ticket.subject}</strong> — <span className={`badge badge-${ticket.status}`}>{ticket.status}</span></p>
        <div style={{maxHeight: 350, overflowY: 'auto', padding: 4}}>
          {messages.map(m => (
            <div key={m.id} className={`timeline-item ${m.author_type === 'admin' ? 'admin' : ''}`}>
              <div style={{fontSize: 12, color: 'var(--muted)', marginBottom: 4}}>
                <strong>{m.author_type === 'admin' ? `${m.author_name} (Support)` : 'Jij'}</strong> — {fmtDate(m.created_at)}
              </div>
              <div style={{whiteSpace: 'pre-wrap'}}>{m.message}</div>
            </div>
          ))}
        </div>
        {ticket.status !== 'closed' && (
          <>
            <h3 className="mt-2">Antwoord typen</h3>
            <textarea rows="4" value={reply} onChange={e => setReply(e.target.value)} placeholder="Typ je bericht..." />
            <div style={{display: 'flex', justifyContent: 'flex-end', gap: 8, marginTop: 8}}>
              <button onClick={onClose}>Sluiten</button>
              <button className="btn-primary" onClick={send} disabled={loading || !reply.trim()}>Versturen</button>
            </div>
          </>
        )}
        {ticket.status === 'closed' && <div className="mt-2 muted">Dit ticket is gesloten. Open een nieuw ticket voor verdere vragen.</div>}
      </div>
    </div>
  );
}

function Credentials({ showToast }) {
  const [creds, setCreds] = useState([]);
  const [loading, setLoading] = useState(true);
  const [showPasswords, setShowPasswords] = useState({});

  useEffect(() => {
    api('/api/customer/credentials').then(c => { setCreds(c); setLoading(false); }).catch(() => { setCreds([]); setLoading(false); });
  }, []);

  const toggle = (id) => setShowPasswords(s => ({...s, [id]: !s[id]}));
  const copy = async (text, label) => {
    try {
      await navigator.clipboard.writeText(text);
      showToast(`${label} gekopieerd`);
    } catch {
      showToast('Kopiëren niet gelukt', 'error');
    }
  };

  if (loading) return <div className="muted">Laden...</div>;

  if (creds.length === 0) {
    return (
      <div>
        <div className="page-header"><h1>🔐 Logingegevens</h1></div>
        <div className="card center muted" style={{padding: 40}}>
          <div style={{fontSize: 40, marginBottom: 12}}>🔐</div>
          Nog geen logingegevens beschikbaar.<br/>
          <span className="small">Zodra je een dienst krijgt waar je op moet inloggen (zoals hosting, WordPress, enz.) verschijnen je inloggegevens hier.</span>
        </div>
      </div>
    );
  }

  return (
    <div>
      <div className="page-header">
        <h1>🔐 Logingegevens</h1>
      </div>
      <div className="card mb-2" style={{background: '#fef3c7', borderColor: '#f59e0b'}}>
        <strong>🔒 Belangrijk:</strong> deel deze gegevens nooit met anderen. WNM-Host vraagt nooit om je wachtwoord per mail of telefoon.
      </div>
      <div className="stack">
        {creds.map(c => (
          <div key={c.id} className="card">
            <div style={{display: 'flex', alignItems: 'center', gap: 12, marginBottom: 12}}>
              <span style={{fontSize: 28}}>{c.icon || '🔐'}</span>
              <div style={{flex: 1}}>
                <strong style={{fontSize: 17}}>{c.title}</strong>
                {c.is_pinned ? <span className="badge badge-new" style={{marginLeft: 8}}>📌 Belangrijk</span> : null}
                {c.order_reference && (
                  <div className="muted small">Bij bestelling {c.order_reference} — {c.order_product_name}</div>
                )}
              </div>
            </div>

            <div style={{display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: 16}}>
              {c.url && (
                <div>
                  <div className="muted small mb-1">Inlogadres</div>
                  <div style={{display: 'flex', gap: 6, alignItems: 'center'}}>
                    <a href={c.url} target="_blank" rel="noopener" className="btn btn-sm btn-primary" style={{flex: 1, textDecoration: 'none'}}>
                      Openen ↗
                    </a>
                    <button className="btn-sm" onClick={() => copy(c.url, 'URL')} title="Kopiëren">📋</button>
                  </div>
                  <div className="muted small mt-1" style={{wordBreak: 'break-all'}}>{c.url}</div>
                </div>
              )}

              {c.username && (
                <div>
                  <div className="muted small mb-1">Gebruikersnaam</div>
                  <div style={{display: 'flex', gap: 6, alignItems: 'center'}}>
                    <code style={{background: '#f3f4f6', padding: '8px 12px', borderRadius: 6, flex: 1, fontSize: 14}}>{c.username}</code>
                    <button className="btn-sm" onClick={() => copy(c.username, 'Gebruikersnaam')} title="Kopiëren">📋</button>
                  </div>
                </div>
              )}

              {c.password && (
                <div>
                  <div className="muted small mb-1">Wachtwoord</div>
                  <div style={{display: 'flex', gap: 6, alignItems: 'center'}}>
                    <code style={{background: '#f3f4f6', padding: '8px 12px', borderRadius: 6, flex: 1, fontSize: 14, fontFamily: 'monospace'}}>
                      {showPasswords[c.id] ? c.password : '••••••••••••'}
                    </code>
                    <button className="btn-sm" onClick={() => toggle(c.id)} title={showPasswords[c.id] ? 'Verbergen' : 'Tonen'}>
                      {showPasswords[c.id] ? '🙈' : '👁'}
                    </button>
                    <button className="btn-sm" onClick={() => copy(c.password, 'Wachtwoord')} title="Kopiëren">📋</button>
                  </div>
                </div>
              )}
            </div>

            {c.notes && (
              <div className="mt-2" style={{padding: 12, background: '#f8fafc', borderRadius: 6, fontSize: 14, whiteSpace: 'pre-wrap'}}>
                <strong className="muted small">📝 Notities:</strong><br/>
                {c.notes}
              </div>
            )}

            <div className="muted small mt-2">Laatst bijgewerkt: {fmtDate(c.updated_at)}</div>
          </div>
        ))}
      </div>
    </div>
  );
}

function renderMd(text) {
  if (!text) return '';
  let h = text
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
  h = h.replace(/^### (.+)$/gm, '<h3>$1</h3>');
  h = h.replace(/^## (.+)$/gm, '<h2>$1</h2>');
  h = h.replace(/^# (.+)$/gm, '<h1>$1</h1>');
  h = h.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>');
  h = h.replace(/\*(.+?)\*/g, '<em>$1</em>');
  h = h.replace(/`([^`]+)`/g, '<code>$1</code>');
  h = h.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (m, label, url) => {
    // Alleen veilige schema's toestaan: http/https of relatief pad. Weiger javascript:/data: e.d.
    const u = String(url).trim();
    const safe = /^(https?:\/\/|\/|#|mailto:)/i.test(u) && !/^javascript:/i.test(u);
    if (!safe) return label;
    return `<a href="${u}" target="_blank" rel="noopener">${label}</a>`;
  });
  h = h.replace(/^- (.+)$/gm, '<li>$1</li>');
  h = h.replace(/(<li>.*?<\/li>(?:\s*<li>.*?<\/li>)*)/gs, '<ul>$1</ul>');
  h = h.split(/\n\n+/).map(p => {
    if (p.startsWith('<h') || p.startsWith('<ul') || p.startsWith('<ol')) return p;
    return '<p>' + p.replace(/\n/g, '<br>') + '</p>';
  }).join('');
  return h;
}

function InfoPages() {
  const [pages, setPages] = useState([]);
  const [active, setActive] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    api('/api/customer/info-pages').then(p => {
      setPages(p);
      setLoading(false);
      if (p.length > 0) {
        const pinned = p.find(x => x.is_pinned) || p[0];
        api(`/api/customer/info-pages/${pinned.id}`).then(setActive);
      }
    });
  }, []);

  const openPage = (id) => api(`/api/customer/info-pages/${id}`).then(setActive);

  if (loading) return <div className="muted">Laden...</div>;

  if (pages.length === 0) {
    return (
      <div>
        <div className="page-header"><h1>Info & uitleg</h1></div>
        <div className="card center muted" style={{padding: 40}}>
          <div style={{fontSize: 40, marginBottom: 12}}>📘</div>
          Nog geen info pagina's beschikbaar.<br/>
          <span className="small">Heb je een vraag over je website? Maak een support ticket aan onder "Support tickets".</span>
        </div>
      </div>
    );
  }

  return (
    <div>
      <div className="page-header"><h1>Info & uitleg</h1></div>
      <p className="muted">Uitleg en handleidingen voor jouw website en diensten bij WNM-Host.</p>

      <div style={{display: 'grid', gridTemplateColumns: '260px 1fr', gap: 20, alignItems: 'flex-start'}}>
        <div className="card" style={{padding: 0, position: 'sticky', top: 16}}>
          {pages.map(p => (
            <div
              key={p.id}
              onClick={() => openPage(p.id)}
              style={{
                padding: '12px 16px', cursor: 'pointer',
                borderBottom: '1px solid var(--border)',
                background: active && active.id === p.id ? '#eff6ff' : '#fff',
                borderLeft: active && active.id === p.id ? '3px solid var(--primary)' : '3px solid transparent',
                display: 'flex', alignItems: 'center', gap: 10,
              }}
            >
              {p.icon && <span style={{fontSize: 18}}>{p.icon}</span>}
              <span style={{flex: 1, fontWeight: active && active.id === p.id ? 600 : 400}}>{p.title}</span>
              {p.is_pinned ? <span style={{color: 'var(--primary)', fontSize: 12}}>📌</span> : null}
            </div>
          ))}
        </div>

        <div className="card">
          {active ? (
            <>
              <div style={{display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16}}>
                {active.icon && <span style={{fontSize: 32}}>{active.icon}</span>}
                <h2 style={{margin: 0}}>{active.title}</h2>
              </div>
              <div style={{lineHeight: 1.7}} dangerouslySetInnerHTML={{ __html: sanitizeHtml(renderMd(active.content)) }} />
              <div className="muted small mt-3" style={{borderTop: '1px solid var(--border)', paddingTop: 12}}>
                Laatst bijgewerkt: {fmtDate(active.updated_at)}
              </div>
            </>
          ) : (
            <div className="muted center">Selecteer een pagina links om te lezen.</div>
          )}
        </div>
      </div>
    </div>
  );
}

function Account({ customer, showToast, refresh }) {
  const [me, setMe] = useState(null);
  const [form, setForm] = useState({});
  const [pw, setPw] = useState({ current_password: '', new_password: '', confirm: '' });
  const [savedAt, setSavedAt] = useState(null);
  const [saving, setSaving] = useState(false);
  const saveTimer = React.useRef(null);

  const load = () => api('/api/customer/me').then(d => { setMe(d); setForm(d); });
  useEffect(() => { load(); }, []);
  useEffect(() => () => clearTimeout(saveTimer.current), []);

  if (!me) return <div className="muted">Laden...</div>;

  const handleChange = (key, value) => {
    setForm(f => ({...f, [key]: value}));
    clearTimeout(saveTimer.current);
    setSaving(true);
    saveTimer.current = setTimeout(async () => {
      try {
        await api('/api/customer/me', { method: 'PUT', body: { ...form, [key]: value } });
        setSavedAt(Date.now());
      } catch (err) {
        showToast('Opslaan mislukt: ' + (err.error || err.message || ''), 'error');
      } finally {
        setSaving(false);
      }
    }, 800);
  };

  const changePw = async (e) => {
    e.preventDefault();
    if (pw.new_password !== pw.confirm) { showToast('Wachtwoorden komen niet overeen', 'error'); return; }
    try {
      const r = await api('/api/auth/customer/change-password', { method: 'POST', body: { current_password: pw.current_password, new_password: pw.new_password } });
      if (r.token) setToken(r.token);
      showToast('Wachtwoord gewijzigd. Andere toestellen zijn uitgelogd.');
      setPw({ current_password: '', new_password: '', confirm: '' });
    } catch (err) { showToast('Wachtwoord wijzigen mislukt: ' + (err.error || err.message || ''), 'error'); }
  };

  const completion = profileCompletion(form);
  const savedAgo = savedAt ? Math.round((Date.now() - savedAt) / 1000) : null;

  const fieldHelp = {
    address: 'Wordt op je facturen vermeld',
    postal_code: 'Wordt op je facturen vermeld',
    city: 'Wordt op je facturen vermeld',
    country: 'Standaard België of Nederland',
    vat_number: 'Indien BTW-plichtig: voor BTW-vrije EU facturatie',
    phone: 'Voor snel contact bij dringende zaken',
  };

  const inputStyle = (key) => ({
    borderColor: !form[key] && !PROFILE_FIELDS.find(f => f.key === key)?.optional ? '#f59e0b' : 'var(--border)',
    background: form[key] ? '#fff' : '#fffbeb',
  });

  return (
    <div>
      <div className="page-header"><h1>Mijn gegevens</h1></div>

      <div className="card mb-2" style={{
        background: completion.percent === 100 ? '#d1fae5' : completion.percent < 50 ? '#fef3c7' : '#dbeafe',
        borderColor: completion.percent === 100 ? '#10b981' : completion.percent < 50 ? '#f59e0b' : 'var(--primary)',
      }}>
        <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 16, flexWrap: 'wrap'}}>
          <div>
            <strong>
              {completion.percent === 100 ? '✓ Profiel volledig ingevuld' : `Profiel ${completion.percent}% volledig`}
            </strong>
            <div className="muted small">
              {completion.filled} van {completion.total} verplichte velden ingevuld
              {completion.missing.length > 0 && ` — nog: ${completion.missing.map(f => f.label).join(', ')}`}
            </div>
          </div>
          <div style={{flex: '0 0 200px', background: '#e5e7eb', borderRadius: 4, height: 10, overflow: 'hidden'}}>
            <div style={{
              background: completion.percent === 100 ? 'var(--success)' : completion.percent < 50 ? 'var(--warning)' : 'var(--primary)',
              height: '100%', width: `${completion.percent}%`, transition: 'width .3s',
            }}></div>
          </div>
        </div>
      </div>

      <div className="card mb-2">
        <div style={{display: 'flex', justifyContent: 'space-between', alignItems: 'center'}}>
          <h3 className="mt-0 mb-0">Inloggegevens</h3>
          <span className="muted small">
            {saving && '⏱ Bezig met opslaan...'}
            {!saving && savedAt && `✓ Opgeslagen ${savedAgo}s geleden`}
          </span>
        </div>
        <p><strong>E-mail (inlognaam):</strong> {me.email}</p>
        <p className="muted small">Klant sinds {fmtDate(me.created_at)}{me.last_login_at && ` — laatste login ${fmtDate(me.last_login_at)}`}</p>
        <p className="muted small">Je e-mailadres is je login en kan niet zelf gewijzigd worden. Wil je een ander e-mailadres? Open een support ticket.</p>
      </div>

      <div className="card">
        <h3 className="mt-0">Contactgegevens</h3>
        <p className="muted small">Wijzigingen worden automatisch opgeslagen tijdens het typen. Velden met gele achtergrond zijn nog leeg en zouden ingevuld moeten zijn voor correcte facturen.</p>
        <div className="grid grid-2 mt-2">
          <div>
            <label>Naam</label>
            <input value={form.name || ''} onChange={e => handleChange('name', e.target.value)} style={inputStyle('name')} />
          </div>
          <div>
            <label>Bedrijf <span className="muted small">(optioneel)</span></label>
            <input value={form.company || ''} onChange={e => handleChange('company', e.target.value)} />
          </div>
          <div>
            <label>Telefoon</label>
            <input value={form.phone || ''} onChange={e => handleChange('phone', e.target.value)} style={inputStyle('phone')} placeholder="bv. +32 470 12 34 56" />
            {fieldHelp.phone && <div className="muted small mt-1">{fieldHelp.phone}</div>}
          </div>
          <div>
            <label>BTW nummer <span className="muted small">(optioneel)</span></label>
            <input value={form.vat_number || ''} onChange={e => handleChange('vat_number', e.target.value)} placeholder="bv. BE0123456789" />
            {fieldHelp.vat_number && <div className="muted small mt-1">{fieldHelp.vat_number}</div>}
          </div>
          <div>
            <label>Adres (straat + nr)</label>
            <input value={form.address || ''} onChange={e => handleChange('address', e.target.value)} style={inputStyle('address')} placeholder="bv. Kerkstraat 12" />
            {fieldHelp.address && <div className="muted small mt-1">{fieldHelp.address}</div>}
          </div>
          <div>
            <label>Postcode</label>
            <input value={form.postal_code || ''} onChange={e => handleChange('postal_code', e.target.value)} style={inputStyle('postal_code')} placeholder="bv. 9000" />
          </div>
          <div>
            <label>Stad</label>
            <input value={form.city || ''} onChange={e => handleChange('city', e.target.value)} style={inputStyle('city')} placeholder="bv. Gent" />
          </div>
          <div>
            <label>Land</label>
            <select value={form.country || ''} onChange={e => handleChange('country', e.target.value)} style={inputStyle('country')}>
              <option value="">— kies een land —</option>
              <option value="BE">België</option>
              <option value="NL">Nederland</option>
              <option value="LU">Luxemburg</option>
              <option value="DE">Duitsland</option>
              <option value="FR">Frankrijk</option>
              <option value="ES">Spanje</option>
              <option value="IT">Italië</option>
              <option value="UK">Verenigd Koninkrijk</option>
              <option value="other">Ander land</option>
            </select>
          </div>
        </div>
      </div>

      <form onSubmit={changePw} className="card mt-2 stack" style={{maxWidth: 500}}>
        <h3 className="mt-0">Wachtwoord wijzigen</h3>
        <div><label>Huidig wachtwoord</label><input type="password" value={pw.current_password} onChange={e => setPw({...pw, current_password: e.target.value})} required /></div>
        <div><label>Nieuw wachtwoord (minimaal 10 tekens)</label><input type="password" value={pw.new_password} onChange={e => setPw({...pw, new_password: e.target.value})} required minLength="10" autoComplete="new-password" /></div>
        <div><label>Bevestig nieuw wachtwoord</label><input type="password" value={pw.confirm} onChange={e => setPw({...pw, confirm: e.target.value})} required /></div>
        <button type="submit" className="btn-primary" style={{alignSelf: 'flex-start'}}>Wachtwoord wijzigen</button>
      </form>

      <div className="card mt-2 stack" style={{maxWidth: 500}}>
        <h3 className="mt-0">Overal uitloggen</h3>
        <p className="muted small" style={{margin: 0}}>Ben je ingelogd op een toestel dat niet van jou is, of vertrouw je het niet? Hiermee log je overal uit, behalve hier.</p>
        <button type="button" style={{alignSelf: 'flex-start'}} onClick={async () => {
          if (!confirm('Overal uitloggen, behalve op dit toestel?')) return;
          try {
            const r = await api('/api/customer/logout-everywhere', { method: 'POST' });
            if (r.token) setToken(r.token);
            showToast('Je bent op alle andere toestellen uitgelogd');
          } catch (err) { showToast('Uitloggen mislukt: ' + (err.error || ''), 'error'); }
        }}>Overal uitloggen</button>
      </div>
    </div>
  );
}

function Licenses({ showToast }) {
  const [list, setList] = useState(null);
  const [open, setOpen] = useState(null); // selected license detail
  const [detail, setDetail] = useState(null);

  const reload = () => api('/api/customer/licenses').then(setList).catch(() => setList([]));
  useEffect(() => { reload(); }, []);

  const openLicense = async (lic) => {
    setOpen(lic);
    setDetail(null);
    try {
      const d = await api('/api/customer/licenses/' + lic.id);
      setDetail(d);
    } catch { setDetail({ ...lic, features: [] }); }
  };

  const copyKey = (key) => {
    navigator.clipboard.writeText(key).then(
      () => showToast && showToast('Licentiesleutel gekopieerd'),
      () => showToast && showToast('Kopiëren mislukt', 'error')
    );
  };

  const statusBadge = (s) => {
    const map = { active: 'paid', trial: 'open', suspended: 'warn', revoked: 'danger', expired: 'danger' };
    return <span className={`badge badge-${map[s] || 'open'}`}>{s}</span>;
  };

  if (!list) return <div className="muted">Laden...</div>;

  return (
    <div>
      <div className="page-header"><h1>🔑 Mijn licenties</h1></div>
      {list.length === 0 ? (
        <div className="card">
          <p className="muted">Je hebt nog geen platform-licenties.</p>
          <p className="muted small">Bekijk onze <a href="/#platformen">platformen</a> of <a href="/#offerte">vraag een offerte aan</a>.</p>
        </div>
      ) : (
        <div className="card">
          <table>
            <thead>
              <tr>
                <th>Platform</th>
                <th>Pakket</th>
                <th>Sleutel</th>
                <th>Status</th>
                <th>Aangemaakt</th>
                <th>Verloopt op</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {list.map(l => (
                <tr key={l.id}>
                  <td><strong>{l.platform_name}</strong></td>
                  <td>{l.package_name}</td>
                  <td>
                    <code style={{fontSize: 12, background: '#f3f4f6', padding: '2px 6px', borderRadius: 4}}>
                      {l.license_key}
                    </code>
                    <button className="btn btn-sm" style={{marginLeft: 6}} onClick={() => copyKey(l.license_key)}>
                      Kopieer
                    </button>
                  </td>
                  <td>{statusBadge(l.status)}</td>
                  <td>{fmtDate(l.created_at)}</td>
                  <td>{l.expires_at ? fmtDate(l.expires_at) : <span className="muted">—</span>}</td>
                  <td className="right">
                    <button className="btn btn-sm" onClick={() => openLicense(l)}>Details</button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {open && (
        <div className="modal-overlay" onClick={() => setOpen(null)}>
          <div className="modal" onClick={e => e.stopPropagation()}>
            <div className="modal-header">
              <h2>{open.platform_name} — {open.package_name}</h2>
              <button className="btn-close" onClick={() => setOpen(null)}>×</button>
            </div>
            <div className="modal-body">
              <div className="card mb-2" style={{background: '#f9fafb'}}>
                <div className="muted small">Licentiesleutel</div>
                <div style={{display: 'flex', alignItems: 'center', gap: 8, marginTop: 4}}>
                  <code style={{fontSize: 15, background: '#fff', padding: '6px 10px', borderRadius: 4, border: '1px solid #e5e7eb', flex: 1}}>
                    {open.license_key}
                  </code>
                  <button className="btn" onClick={() => copyKey(open.license_key)}>Kopieer</button>
                </div>
              </div>

              <div className="grid grid-2 mb-2">
                <div><div className="muted small">Status</div><div>{statusBadge(open.status)}</div></div>
                <div><div className="muted small">Pakket</div><div>{open.package_name} ({fmtMoney(open.price_cents)}/{open.billing_cycle})</div></div>
                <div><div className="muted small">Aangemaakt</div><div>{fmtDate(open.created_at)}</div></div>
                <div><div className="muted small">Verloopt op</div><div>{open.expires_at ? fmtDate(open.expires_at) : <span className="muted">Onbeperkt</span>}</div></div>
                {open.instance_url && (
                  <div style={{gridColumn: '1 / -1'}}>
                    <div className="muted small">Jouw platform</div>
                    <div><a href={open.instance_url} target="_blank" rel="noopener noreferrer">{open.instance_url} ↗</a></div>
                  </div>
                )}
                {open.last_verified_at && (
                  <div style={{gridColumn: '1 / -1'}}>
                    <div className="muted small">Laatst geverifieerd</div>
                    <div>{fmtDate(open.last_verified_at)}</div>
                  </div>
                )}
              </div>

              {detail && detail.features && detail.features.length > 0 && (
                <div className="card">
                  <h3 className="mt-0">Inbegrepen functies</h3>
                  <table>
                    <thead>
                      <tr>
                        <th>Functie</th>
                        <th>Categorie</th>
                        <th className="right">Limiet</th>
                      </tr>
                    </thead>
                    <tbody>
                      {detail.features.filter(f => f.included).map(f => (
                        <tr key={f.slug}>
                          <td>
                            <strong>{f.name}</strong>
                            {f.description && <div className="muted small">{f.description}</div>}
                          </td>
                          <td><span className="muted small">{f.category || '—'}</span></td>
                          <td className="right">{f.limit_value || <span className="muted">∞</span>}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}

              {detail && detail.app && (
                <div className="card mt-2">
                  <h3 className="mt-0">📱 Eigen app</h3>
                  <div className="grid grid-2">
                    <div><div className="muted small">App</div><div><strong>{detail.app.appName}</strong></div></div>
                    <div><div className="muted small">Status</div><div><span className="badge badge-open">{detail.app.statusLabel}</span></div></div>
                    {detail.app.appStoreUrl && (
                      <div style={{gridColumn: '1 / -1'}}>
                        <div className="muted small">App Store</div>
                        <div><a href={detail.app.appStoreUrl} target="_blank" rel="noopener noreferrer">{detail.app.appStoreUrl} ↗</a></div>
                      </div>
                    )}
                  </div>
                  <p className="muted small" style={{marginBottom: 0}}>Je aanvraag volg je op en pas je aan in het beheer van je platform, onder "Eigen app".</p>
                </div>
              )}

              {open.notes && (
                <div className="card mt-2">
                  <div className="muted small">Notities</div>
                  <div style={{whiteSpace: 'pre-wrap'}}>{open.notes}</div>
                </div>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function PaymentStatus() {
  const params = new URLSearchParams(window.location.hash.split('?')[1] || '');
  return (
    <div className="login-shell">
      <div className="login-card center">
        <h1>Bedankt!</h1>
        <p>Je betaling wordt verwerkt. Je ontvangt zo een bevestiging per e-mail.</p>
        <p className="muted">Referentie: <strong>{params.get('ref')}</strong></p>
        <a href="/klant" className="btn btn-primary mt-2">Naar mijn klantenpaneel</a>
      </div>
    </div>
  );
}

function CustomerAnnouncements({ showToast, onChange }) {
  const [data, setData] = useState({ announcements: [], unread_count: 0 });
  const [loading, setLoading] = useState(true);
  const [busy, setBusy] = useState(null);

  const load = () => api('/api/customer/announcements')
    .then(d => { setData(d); if (onChange) onChange(d.unread_count || 0); })
    .catch(() => {})
    .finally(() => setLoading(false));

  useEffect(() => { load(); }, []);

  // Markeer alle ongelezen items automatisch als gelezen wanneer ze in beeld komen
  useEffect(() => {
    if (loading) return;
    const unread = (data.announcements || []).filter(a => !a.read_at);
    if (unread.length === 0) return;
    Promise.all(unread.map(a =>
      api(`/api/customer/announcements/${a.id}/read`, { method: 'POST' }).catch(() => {})
    )).then(() => load());
  }, [loading]);

  const dismiss = async (id) => {
    setBusy(id);
    try {
      await api(`/api/customer/announcements/${id}/dismiss`, { method: 'POST' });
      await load();
    } catch (e) { showToast('Mislukt: ' + (e.error || e.message || ''), 'error'); }
    finally { setBusy(null); }
  };

  const fmt = (d) => { if (!d) return ''; try { return new Date(d).toLocaleString('nl-BE', { day: '2-digit', month: 'short', year: 'numeric', hour: '2-digit', minute: '2-digit' }); } catch { return d; } };
  const styleFor = (c) => {
    if (c === 'warning') return { border: '#f59e0b', bg: '#fffbeb', icon: '⚠️' };
    if (c === 'success') return { border: '#10b981', bg: '#ecfdf5', icon: '✅' };
    return { border: '#3b82f6', bg: '#eff6ff', icon: 'ℹ️' };
  };

  if (loading) return <div><h1>📢 Mededelingen</h1><p className="muted">Laden…</p></div>;

  return (
    <div>
      <h1>📢 Mededelingen</h1>
      <p className="muted small">Berichten van het WNM-Host team. Open een bericht om het als gelezen te markeren, of klik op “Wegklikken” om het uit je lijst te halen.</p>

      {(data.announcements || []).length === 0 ? (
        <div className="card center" style={{ padding: 40 }}>
          <div style={{ fontSize: 48, marginBottom: 8 }}>📭</div>
          <p className="muted">Geen mededelingen op dit moment.</p>
        </div>
      ) : (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          {data.announcements.map(a => {
            const s = styleFor(a.category);
            return (
              <div key={a.id} className="card" style={{ borderLeft: `4px solid ${s.border}`, background: s.bg }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: 12 }}>
                  <div style={{ flex: 1 }}>
                    <h3 style={{ marginTop: 0, display: 'flex', alignItems: 'center', gap: 8 }}>
                      <span>{s.icon}</span>
                      <span>{a.title}</span>
                      {!a.read_at && <span style={{ background: '#ef4444', color: '#fff', borderRadius: 4, padding: '2px 6px', fontSize: 10, fontWeight: 700 }}>NIEUW</span>}
                    </h3>
                    <p className="muted small" style={{ marginTop: -4 }}>{fmt(a.created_at)}</p>
                    <div style={{ marginTop: 8 }} dangerouslySetInnerHTML={{ __html: sanitizeHtml(a.body_html) }} />
                  </div>
                  <button className="btn-sm" onClick={() => dismiss(a.id)} disabled={busy === a.id} title="Wegklikken">
                    {busy === a.id ? '…' : '✕ Wegklikken'}
                  </button>
                </div>
              </div>
            );
          })}
        </div>
      )}
    </div>
  );
}

function App() {
  const [customer, setCustomer] = useState(null);
  const [loading, setLoading] = useState(true);
  const [active, setActive] = useState('dashboard');
  const [unreadAnnouncements, setUnreadAnnouncements] = useState(0);
  const [toast, showToast] = useToast();
  const [dark, toggleDark] = useDarkMode();

  useEffect(() => {
    const handleHash = () => {
      if (window.location.hash.startsWith('#/betaling-status')) {
        // handled in render
      }
    };
    window.addEventListener('hashchange', handleHash);
    return () => window.removeEventListener('hashchange', handleHash);
  }, []);

  useEffect(() => {
    if (!getToken()) { setLoading(false); return; }
    api('/api/customer/me').then(c => setCustomer({ id: c.id, email: c.email, name: c.name, company: c.company })).catch(() => setToken(null)).finally(() => setLoading(false));
  }, []);

  // Unread mededelingen ophalen zodra de klant is ingelogd
  useEffect(() => {
    if (!customer) return;
    api('/api/customer/announcements').then(d => setUnreadAnnouncements(d.unread_count || 0)).catch(() => {});
  }, [customer]);

  if (window.location.hash.startsWith('#/betaling-status')) {
    return <PaymentStatus />;
  }

  if (loading) return <div className="login-shell"><div className="muted">Laden...</div></div>;
  if (!customer) return <Login onLogin={setCustomer} />;

  const logout = () => { setToken(null); setCustomer(null); };

  let content;
  if (active === 'dashboard') content = <Dashboard customer={customer} setActive={setActive} />;
  else if (active === 'announcements') content = <CustomerAnnouncements showToast={showToast} onChange={setUnreadAnnouncements} />;
  else if (active === 'credentials') content = <Credentials showToast={showToast} />;
  else if (active === 'info') content = <InfoPages />;
  else if (active === 'quotes') content = <Quotes showToast={showToast} setActive={setActive} />;
  else if (active === 'orders') content = <Orders />;
  else if (active === 'invoices') content = <Invoices />;
  else if (active === 'licenses') content = <Licenses showToast={showToast} />;
  else if (active === 'tickets') content = <Tickets showToast={showToast} />;
  else if (active === 'account') content = <Account customer={customer} showToast={showToast} />;

  return (
    <div className="panel-shell">
      <Sidebar active={active} setActive={setActive} customer={customer} onLogout={logout} unreadCount={unreadAnnouncements} dark={dark} toggleDark={toggleDark} />
      <main className="main">{content}</main>
      <Toast toast={toast} />
    </div>
  );
}

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