// views/quotes.jsx — quotations and proforma invoices, and turning them into invoices.
// Quotes live in their own table, so nothing that adds up invoices — GST,
// receivables, TCS, the books — ever sees them.

function qToken() {
  const a = new Uint8Array(16); window.crypto.getRandomValues(a);
  return Array.from(a, b => b.toString(36).padStart(2, '0')).join('').slice(0, 24);
}
const Q_KIND = { quote: { label: 'Quotation', short: 'Quote', code: 'QT' }, proforma: { label: 'Proforma invoice', short: 'Proforma', code: 'PI' } };

function qFy(date) {
  const d = new Date(String(date).slice(0, 10) + 'T00:00:00');
  const y = d.getMonth() >= 3 ? d.getFullYear() : d.getFullYear() - 1;
  return String(y % 100).padStart(2, '0') + '-' + String((y + 1) % 100).padStart(2, '0');
}

Object.assign(Store, {
  nextQuoteNumber(kind, date) {
    const st = Store.get();
    const prefix = (st.invoicePrefix || 'LU') + '/' + Q_KIND[kind].code + '/' + qFy(date) + '/';
    const used = (st.quotes || []).map(q => q.number).filter(n => n && n.indexOf(prefix) === 0).map(n => parseInt(n.slice(prefix.length), 10) || 0);
    return prefix + String((used.length ? Math.max.apply(null, used) : 0) + 1).padStart(3, '0');
  },
  addQuote(q) {
    const date = q.date || new Date().toISOString().slice(0, 10);
    const kind = q.kind || 'quote';
    const valid = new Date(date + 'T00:00:00'); valid.setDate(valid.getDate() + 14);
    const id = 'q' + Date.now().toString(36);
    const next = {
      id, kind, number: Store.nextQuoteNumber(kind, date), date,
      valid_until: q.valid_until || (valid.getFullYear() + '-' + String(valid.getMonth() + 1).padStart(2, '0') + '-' + String(valid.getDate()).padStart(2, '0')),
      customer_id: null, customer_name: '', customer_address: '', customer_gstin: '', customer_email: '', customer_pan: '',
      booking_id: null, title: '', itemised: false, items: [], subtotal: 0,
      gst_enabled: false, gst_rate: null, tcs_rate: null, place_of_supply: '', sac_code: '',
      notes: '', terms: '', cancellation: '', status: 'draft', share_token: qToken(), invoice_id: null,
      ...q, id, date,
    };
    Store.set(s => ({ ...s, quotes: [...(s.quotes || []), next] }));
    return id;
  },
  updateQuote(id, patch) { Store.set(s => ({ ...s, quotes: (s.quotes || []).map(q => q.id === id ? { ...q, ...patch } : q) })); },
  removeQuote(id) { Store.set(s => ({ ...s, quotes: (s.quotes || []).filter(q => q.id !== id) })); },
  // Accepted: copy everything billable onto a fresh draft invoice with the
  // next number in the real series, and point the quote at it.
  convertQuote(id) {
    const q = (Store.get().quotes || []).find(x => x.id === id);
    if (!q) return null;
    const today = new Date().toISOString().slice(0, 10);
    const keep = ['customer_id', 'customer_name', 'customer_address', 'customer_gstin', 'customer_email', 'customer_pan', 'booking_id', 'title',
      'itemised', 'items', 'subtotal', 'gst_enabled', 'gst_rate', 'tcs_rate', 'place_of_supply', 'sac_code', 'terms', 'cancellation', 'signatory'];
    const inv = { date: today, due_date: today, status: 'draft', notes: [q.notes, 'Ref: ' + Q_KIND[q.kind].label + ' ' + q.number].filter(Boolean).join('\n') };
    keep.forEach(k => { if (q[k] !== undefined) inv[k] = q[k]; });
    const invId = Store.addInvoice(inv);
    // addInvoice only takes its own fields; carry the rest across after.
    Store.updateInvoice(invId, { customer_email: q.customer_email || '', customer_pan: q.customer_pan || '' });
    Store.updateQuote(id, { status: 'accepted', invoice_id: invId, accepted_at: new Date().toISOString() });
    return invId;
  },
});

function qStatus(q) {
  if (q.status === 'sent' && q.valid_until && q.valid_until < new Date().toISOString().slice(0, 10)) return 'expired';
  return q.status || 'draft';
}
function QStatusTag({ q }) {
  const st = qStatus(q);
  const cls = { draft: 'tag-empty', sent: 'tag-transfer', accepted: 'tag-income', declined: 'tag-empty', expired: 'tag-expense' }[st] || 'tag-empty';
  return <span className={'tag ' + cls}>{st}</span>;
}
function qPrint(q) {
  const safe = s => String(s || '').replace(/[\\/:*?"<>|]+/g, '-').replace(/\s+/g, ' ').trim();
  const prev = document.title;
  document.title = Q_KIND[q.kind].label + ' ' + safe(q.number) + ' - ' + safe(q.customer_name);
  window.print();
  setTimeout(() => { document.title = prev; }, 1000);
}

function QuotesView({ onBack, onOpenInvoice }) {
  const s = useStore();
  const books = useBooks();
  const firm = books.firm || {};
  const [editId, setEditId] = React.useState(null);
  const [q, setQ] = React.useState('');
  const [show, setShow] = React.useState('open');
  const quotes = s.quotes || [];
  const today = new Date().toISOString().slice(0, 10);

  if (editId) {
    const cur = quotes.find(x => x.id === editId);
    if (cur) return <QuoteEditor q={cur} s={s} firm={firm} onClose={() => setEditId(null)} onOpenInvoice={onOpenInvoice} />;
  }
  function create(kind) {
    setEditId(Store.addQuote({ kind, date: today, terms: firm.default_terms || '', cancellation: firm.default_cancellation || '',
      gst_enabled: !!firm.gstin, gst_rate: firm.gstin ? 5 : null, sac_code: firm.gstin ? '998552' : '', signatory: firm.default_signatory || 'prateek' }));
  }
  const shown = quotes
    .filter(x => show === 'all' ? true : show === 'open' ? ['draft', 'sent'].includes(qStatus(x)) : qStatus(x) === show)
    .filter(x => !q || ((x.number || '') + ' ' + (x.customer_name || '') + ' ' + (x.title || '')).toLowerCase().includes(q.toLowerCase()))
    .sort((a, b) => (b.date || '').localeCompare(a.date || '') || (b.number || '').localeCompare(a.number || ''));
  const openVal = quotes.filter(x => qStatus(x) === 'sent').reduce((a, x) => a + invTotals(x).total, 0);
  const won = quotes.filter(x => x.status === 'accepted').length;
  const decided = quotes.filter(x => ['accepted', 'declined'].includes(x.status) || qStatus(x) === 'expired').length;

  return (
    <div>
      <div className="page-head">
        <div>
          <h1 className="page-title">Quotes <em>&amp;</em> proforma.</h1>
          <p className="page-sub">Price a trip before it's confirmed. Accepted quotes turn into a draft invoice in one click. None of this touches GST, receivables or the books.</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-ghost" onClick={onBack}>← Invoices</button>
          <button className="btn" onClick={() => create('proforma')}>New proforma</button>
          <button className="btn btn-primary" onClick={() => create('quote')}>New quote</button>
        </div>
      </div>
      <div className="books-kpi-row">
        <div className="card"><div className="bk-label">Out with clients</div><div className="bk-val">{fmtINR(openVal)}</div><div className="bk-note">{quotes.filter(x => qStatus(x) === 'sent').length} sent, awaiting a yes</div></div>
        <div className="card"><div className="bk-label">Accepted</div><div className="bk-val t-credit">{won}</div><div className="bk-note">{decided ? Math.round(won / decided * 100) + '% of decided' : 'none decided yet'}</div></div>
        <div className="card"><div className="bk-label">Expiring in 3 days</div><div className="bk-val">{quotes.filter(x => x.status === 'sent' && x.valid_until >= today && x.valid_until <= new Date(Date.now() + 3 * 864e5).toISOString().slice(0, 10)).length}</div></div>
      </div>
      <div className="toolbar" style={{ marginTop: 16 }}>
        <div className="search">
          <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2"><circle cx="11" cy="11" r="7" /><path d="m21 21-4.3-4.3" /></svg>
          <input placeholder="Search number, client, trip…" value={q} onChange={e => setQ(e.target.value)} />
        </div>
        <div className="sep"></div>
        <FilterSelect label="Show" value={show} options={[{ value: 'open', label: 'Open' }, { value: 'all', label: 'All' }, { value: 'accepted', label: 'Accepted' }, { value: 'declined', label: 'Declined' }, { value: 'expired', label: 'Expired' }]} onChange={setShow} />
        <div style={{ flex: 1 }}></div>
        <span className="muted" style={{ fontSize: 12 }}>{shown.length} shown</span>
      </div>
      <div className="card" style={{ padding: 0 }}>
        <table className="tbl">
          <thead><tr><th style={{ width: 150 }}>Number</th><th style={{ width: 88 }}>Date</th><th>Client / trip</th><th style={{ width: 96 }}>Valid until</th><th style={{ width: 170 }}>Status</th><th style={{ width: 130, textAlign: 'right' }}>Total</th></tr></thead>
          <tbody>
            {shown.map(x => {
              const inv = x.invoice_id ? (s.invoices || []).find(i => i.id === x.invoice_id) : null;
              return (
                <tr key={x.id} onClick={() => setEditId(x.id)} style={{ cursor: 'pointer' }}>
                  <td><div className="mono" style={{ fontSize: 11.5, fontWeight: 600 }}>{x.number}</div><div className="muted" style={{ fontSize: 10 }}>{Q_KIND[x.kind].short}</div></td>
                  <td className="num" style={{ fontSize: 12 }}>{fmtDate(x.date)}</td>
                  <td><div style={{ fontSize: 12.5, fontWeight: 500 }}>{x.customer_name || <span className="muted">No client</span>}</div><div className="muted" style={{ fontSize: 10.5 }}>{x.title || '—'}</div></td>
                  <td className="num" style={{ fontSize: 12 }}>{fmtDate(x.valid_until)}</td>
                  <td><QStatusTag q={x} />{inv && <span className="muted mono" style={{ fontSize: 10.5, marginLeft: 6 }}>→ {inv.number}</span>}</td>
                  <td className="num" style={{ textAlign: 'right', fontSize: 12, fontWeight: 600 }}>{fmtINR(invTotals(x).total)}</td>
                </tr>
              );
            })}
            {!shown.length && <tr><td colSpan={6} style={{ textAlign: 'center', padding: 40, color: 'var(--ink-3)' }}>{quotes.length ? 'Nothing matches these filters.' : 'No quotes yet. Press New quote to price your first trip.'}</td></tr>}
          </tbody>
        </table>
      </div>
    </div>
  );
}

function QuoteEditor({ q, s, firm, onClose, onOpenInvoice }) {
  const [preview, setPreview] = React.useState(false);
  const [mail, setMail] = React.useState(false);
  const set = patch => Store.updateQuote(q.id, patch);
  const t = invTotals(q);
  const gstOn = !!firm.gstin;
  const K = Q_KIND[q.kind];
  const link = location.origin + '/i/' + q.share_token;
  const live = q.status !== 'draft';
  const inv = q.invoice_id ? (s.invoices || []).find(i => i.id === q.invoice_id) : null;
  const docQ = { ...q, doc_kind: q.kind };

  function setItem(i, patch) { set({ items: (q.items || []).map((r, j) => j === i ? { ...r, ...patch } : r) }); }
  function pickCustomer(name) {
    const c = (s.customers || []).find(x => x.name === name);
    set(c ? { customer_name: c.name, customer_id: c.id, customer_gstin: c.gstin || q.customer_gstin } : { customer_name: name, customer_id: null });
  }
  function ensureSent() {
    if (q.status === 'draft') { set({ status: 'sent', sent_at: new Date().toISOString() }); }
  }
  function whatsapp() {
    ensureSent();
    const text = [(firm.name || 'Luxury Unlocked') + ' — ' + K.label.toLowerCase() + ' ' + q.number, q.title, 'Total ' + invINR(t.total), q.valid_until ? 'Valid until ' + invDate(q.valid_until) : '', '', link].filter(x => x !== '').join('\n');
    window.open('https://wa.me/?text=' + encodeURIComponent(text), '_blank');
  }
  function convert() {
    if (!q.customer_name) { alert('Add the client first.'); return; }
    if (!confirm('Turn ' + q.number + ' into a draft invoice?\n\nIt gets the next number in your invoice series, and the ' + K.short.toLowerCase() + ' is marked accepted.')) return;
    const id = Store.convertQuote(q.id);
    if (id && onOpenInvoice) onOpenInvoice(id);
  }

  if (preview) {
    return (
      <div>
        <div className="page-head no-print">
          <div><h1 className="page-title">{K.label} <em>preview</em>.</h1><p className="page-sub">What your client sees. Print or save as PDF from here.</p></div>
          <div className="page-actions">
            <button className="btn btn-ghost" onClick={() => setPreview(false)}>← Back to editing</button>
            <button className="btn btn-primary" onClick={() => qPrint(q)}>Print / save PDF</button>
          </div>
        </div>
        <div className="inv-page-wrap"><InvoiceDoc inv={docQ} firm={firm} paid={0} payments={[]} /></div>
      </div>
    );
  }

  return (
    <div>
      {mail && <EmailCompose inv={docQ} firm={firm} kind={q.kind} link={link} onClose={() => setMail(false)} onSent={() => { ensureSent(); setMail(false); }} />}
      <div className="page-head">
        <div>
          <h1 className="page-title">{q.number} <em>·</em> {q.customer_name || 'unnamed'}</h1>
          <p className="page-sub">{K.label} · total {fmtINR(t.total)}{q.valid_until ? ' · valid until ' + fmtDateFull(q.valid_until) : ''}</p>
        </div>
        <div className="page-actions">
          <button className="btn btn-ghost" onClick={onClose}>← All quotes</button>
          <button className="btn" onClick={() => setPreview(true)}>Preview</button>
        </div>
      </div>

      <div className="split-books">
        <div>
          <div className="card">
            <div className="rule-label">Client</div>
            <div className="form-grid" style={{ marginTop: 10 }}>
              <div><label className="field-label">Name</label>
                <input className="input" list="q-customers" value={q.customer_name || ''} onChange={e => pickCustomer(e.target.value)} placeholder="Client or family name" />
                <datalist id="q-customers">{(s.customers || []).map(c => <option key={c.id} value={c.name} />)}</datalist>
              </div>
              <div><label className="field-label">Email</label><input className="input" value={q.customer_email || ''} onChange={e => set({ customer_email: e.target.value })} placeholder="client@example.com" /></div>
              <div style={{ gridColumn: '1 / -1' }}><label className="field-label">Address</label><textarea className="input" rows="2" value={q.customer_address || ''} onChange={e => set({ customer_address: e.target.value })} /></div>
              {gstOn && <div><label className="field-label">GSTIN</label><input className="input mono" value={q.customer_gstin || ''} onChange={e => set({ customer_gstin: e.target.value.toUpperCase() })} placeholder="if a business" /></div>}
              <div><label className="field-label">Booking</label>
                <select className="select" value={q.booking_id || ''} onChange={e => set({ booking_id: e.target.value || null })}>
                  <option value="">— not linked —</option>
                  {(s.bookings || []).filter(b => b.status !== 'cancelled').map(b => <option key={b.id} value={b.id}>{(b.tour || 'Untitled') + (b.start ? ' · ' + fmtDateFull(b.start) : '')}</option>)}
                </select>
              </div>
            </div>
          </div>

          <div className="card" style={{ marginTop: 14 }}>
            <div className="row gap-2" style={{ justifyContent: 'space-between', alignItems: 'center' }}>
              <div className="rule-label">What's included</div>
              <div className="seg">{[[false, 'One amount'], [true, 'Itemised']].map(([v, l]) => <div key={l} className={'seg-btn ' + (!!q.itemised === v ? 'active' : '')} onClick={() => set({ itemised: v, ...(v && !(q.items || []).length ? { items: [{ desc: q.title || '', qty: 1, rate: Number(q.subtotal) || 0 }] } : {}) })}>{l}</div>)}</div>
            </div>
            <div style={{ marginTop: 10 }}><label className="field-label">Trip</label><input className="input" value={q.title || ''} onChange={e => set({ title: e.target.value })} placeholder="7 nights · Masai Mara & Amboseli · 2 adults" /></div>
            {!q.itemised ? (
              <div style={{ marginTop: 10, maxWidth: 260 }}><label className="field-label">Package price (before tax)</label><input className="input num" type="number" value={q.subtotal || ''} onChange={e => set({ subtotal: Number(e.target.value) || 0 })} /></div>
            ) : (
              <table className="tbl" style={{ marginTop: 10 }}>
                <thead><tr><th>Description</th><th style={{ width: 70 }}>Qty</th><th style={{ width: 130 }}>Rate</th><th style={{ width: 120, textAlign: 'right' }}>Amount</th><th style={{ width: 30 }}></th></tr></thead>
                <tbody>
                  {(q.items || []).map((r, i) => (
                    <tr key={i}>
                      <td><input className="input input-xs" value={r.desc || ''} onChange={e => setItem(i, { desc: e.target.value })} placeholder="Camp, flights, transfers…" /></td>
                      <td><input className="input input-xs num" type="number" value={r.qty ?? 1} onChange={e => setItem(i, { qty: Number(e.target.value) || 0 })} /></td>
                      <td><input className="input input-xs num" type="number" value={r.rate || ''} onChange={e => setItem(i, { rate: Number(e.target.value) || 0, amount: undefined })} /></td>
                      <td className="num" style={{ textAlign: 'right', fontSize: 12 }}>{fmtINR((Number(r.qty) || 0) * (Number(r.rate) || 0))}</td>
                      <td><button className="btn btn-sm btn-ghost" onClick={() => set({ items: (q.items || []).filter((_, j) => j !== i) })}>×</button></td>
                    </tr>
                  ))}
                </tbody>
              </table>
            )}
            {q.itemised && <button className="btn btn-sm" style={{ marginTop: 8 }} onClick={() => set({ items: [...(q.items || []), { desc: '', qty: 1, rate: 0 }] })}>+ Line</button>}
          </div>

          <div className="card" style={{ marginTop: 14 }}>
            <div className="form-grid">
              <div style={{ gridColumn: '1 / -1' }}><label className="field-label">Notes for the client</label><textarea className="input" rows="3" value={q.notes || ''} onChange={e => set({ notes: e.target.value })} placeholder="Inclusions, exclusions, what's on hold…" /></div>
              <div style={{ gridColumn: '1 / -1' }}><label className="field-label">Payment terms</label><textarea className="input" rows="2" value={q.terms || ''} onChange={e => set({ terms: e.target.value })} /></div>
              <div style={{ gridColumn: '1 / -1' }}><label className="field-label">Cancellation policy</label><textarea className="input" rows="3" value={q.cancellation || ''} onChange={e => set({ cancellation: e.target.value })} /></div>
            </div>
          </div>
        </div>

        <div>
          <div className="panel">
            <div className="rule-label">{K.label}</div>
            <div className="panel-section" style={{ marginTop: 10 }}>
              <div className="seg">{['quote', 'proforma'].map(k => <div key={k} className={'seg-btn ' + (q.kind === k ? 'active' : '')} onClick={() => { if (k !== q.kind && q.status === 'draft') set({ kind: k, number: Store.nextQuoteNumber(k, q.date) }); }}>{Q_KIND[k].short}</div>)}</div>
              <div className="muted" style={{ fontSize: 10, lineHeight: 1.5, marginTop: 6 }}>{q.kind === 'quote' ? 'A priced offer. No payment asked for yet.' : 'Asks for an advance before the trip is confirmed. Not a tax invoice — the invoice follows once paid.'}{q.status !== 'draft' ? ' Type is fixed once sent.' : ''}</div>
            </div>
            <SignatoryPicker doc={q} firm={firm} onPick={id => set({ signatory: id })} />
            <div className="panel-section"><label className="field-label">Number</label><input className="input mono" value={q.number || ''} onChange={e => set({ number: e.target.value })} /></div>
            <div className="panel-section"><label className="field-label">Date</label><input className="input" type="date" value={q.date || ''} onChange={e => set({ date: e.target.value })} /></div>
            <div className="panel-section"><label className="field-label">Valid until</label><input className="input" type="date" value={q.valid_until || ''} onChange={e => set({ valid_until: e.target.value })} />
              <div className="pills" style={{ marginTop: 6 }}>{[7, 14, 30].map(d => <div key={d} className="pill" onClick={() => { const x = new Date((q.date || new Date().toISOString().slice(0, 10)) + 'T00:00:00'); x.setDate(x.getDate() + d); set({ valid_until: x.getFullYear() + '-' + String(x.getMonth() + 1).padStart(2, '0') + '-' + String(x.getDate()).padStart(2, '0') }); }}>{d} days</div>)}</div>
            </div>

            {gstOn && (
              <div className="panel-section">
                <label className="field-label">GST</label>
                <div className="pills">
                  {[5, 18].map(r => <div key={r} className={'pill ' + (q.gst_enabled && Number(q.gst_rate) === r ? 'active' : '')} onClick={() => set({ gst_enabled: true, gst_rate: r })}>{r}%</div>)}
                  <div className={'pill ' + (!q.gst_enabled ? 'active' : '')} onClick={() => set({ gst_enabled: false, gst_rate: null })}>none</div>
                </div>
                <select className="select" style={{ marginTop: 8 }} value={/^\d{2}-/.test(q.place_of_supply || '') ? q.place_of_supply : ''} onChange={e => set({ place_of_supply: e.target.value })}>
                  <option value="">Place of supply…</option>
                  {Object.keys(INV_STATES).map(k => <option key={k} value={k + '-' + INV_STATES[k]}>{k} · {INV_STATES[k]}</option>)}
                </select>
              </div>
            )}
            <div className="panel-section">
              <label className="field-label">TCS · {tcsSection(q.date)}</label>
              <div className="pills">
                {[2, 5, 20].map(r => <div key={r} className={'pill ' + (Number(q.tcs_rate) === r ? 'active' : '')} onClick={() => set({ tcs_rate: Number(q.tcs_rate) === r ? null : r })}>{r}%</div>)}
                <div className={'pill ' + (!q.tcs_rate ? 'active' : '')} onClick={() => set({ tcs_rate: null })}>none</div>
              </div>
              <div className="muted" style={{ fontSize: 10, lineHeight: 1.5 }}>Overseas packages. Shown so the client sees the full amount upfront.</div>
            </div>

            <div className="inv-total-box">
              <div><span>Subtotal</span><b className="num">{fmtINR(t.sub)}</b></div>
              {t.gst > 0 && (gstOn ? invGstSplit(q, firm, t.gst).rows.map(r => <div key={r.label}><span>{r.label} {r.rate}%</span><b className="num">{fmtINR(r.amt)}</b></div>) : <div><span>GST</span><b className="num">{fmtINR(t.gst)}</b></div>)}
              {t.tcs > 0 && <div><span>TCS</span><b className="num">{fmtINR(t.tcs)}</b></div>}
              <div className="inv-total-final"><span>Total</span><b className="num">{fmtINR(t.total)}</b></div>
            </div>

            <div className="panel-section">
              <label className="field-label">Status</label>
              <div className="pills">
                {['draft', 'sent', 'accepted', 'declined'].map(st => <div key={st} className={'pill ' + (q.status === st ? 'active' : '')} onClick={() => { if (st === 'accepted' && !inv) { convert(); return; } set({ status: st }); }}>{st}</div>)}
              </div>
              {qStatus(q) === 'expired' && <div className="t-debit" style={{ fontSize: 10.5, lineHeight: 1.5 }}>Past its validity date. Extend it or mark it declined.</div>}
            </div>

            <div className="panel-section">
              <label className="field-label">{inv ? 'Invoice' : 'Accepted?'}</label>
              {inv
                ? <button className="btn btn-sm" onClick={() => onOpenInvoice && onOpenInvoice(inv.id)}>Open invoice {inv.number} →</button>
                : <><button className="btn btn-primary" style={{ width: '100%' }} onClick={convert}>Convert to invoice</button>
                    <div className="muted" style={{ fontSize: 10, lineHeight: 1.5, marginTop: 6 }}>Copies the client, trip, lines, GST and terms onto a new draft invoice with the next real number.</div></>}
            </div>

            <div className="panel-section">
              <label className="field-label">Send it</label>
              <div className="row gap-2" style={{ flexWrap: 'wrap' }}>
                <button className="btn btn-sm" onClick={() => setMail(true)}>Email</button>
                <button className="btn btn-sm" onClick={whatsapp}>WhatsApp</button>
                <button className="btn btn-sm btn-ghost" onClick={() => { ensureSent(); (navigator.clipboard ? navigator.clipboard.writeText(link) : Promise.reject()).then(() => alert('Link copied:\n' + link), () => prompt('Copy this link:', link)); }}>Copy link</button>
              </div>
              <div className="muted" style={{ fontSize: 10, lineHeight: 1.5, marginTop: 6 }}>{live ? 'The client link is live.' : 'Sending marks it as sent and switches the client link on.'}</div>
            </div>

            <div className="row gap-2" style={{ marginTop: 16, alignItems: 'center' }}>
              <button className="btn btn-sm btn-ghost" onClick={() => { if (confirm('Delete ' + q.number + '?')) { Store.removeQuote(q.id); onClose(); } }}>Delete</button>
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function SignatoryPicker({ doc, firm, onPick }) {
  const cur = invSigner(doc, firm);
  return (
    <div className="panel-section">
      <label className="field-label">Signed by</label>
      <div className="seg">{invSigners(firm).map(sg => <div key={sg.id} className={'seg-btn ' + (cur.id === sg.id ? 'active' : '')} onClick={() => onPick(sg.id)}>{sg.name}</div>)}</div>
      <div className="muted" style={{ fontSize: 10, lineHeight: 1.5, marginTop: 4 }}>{cur.title}{!cur.signature ? ' · no signature uploaded yet' : ''}</div>
    </div>
  );
}

Object.assign(window, { SignatoryPicker, QuotesView, QuoteEditor, Q_KIND, qStatus });
