// views/payments.jsx — Razorpay payment links per invoice.
// Links and their payments live in the pay_links table, written only by the
// razorpay Edge Function. The app reads them and counts them as received.

function rzpPaymentsFor(s, invId) {
  const out = [];
  (s.payLinks || []).filter(l => l.invoice_id === invId).forEach(l => (l.payments || []).forEach(p =>
    out.push({ id: p.id, date: p.date, amount: Number(p.amount) || 0, mode: p.method || 'Razorpay', rzp: true })));
  return out;
}
function rzpPaidFor(s, invId) { return Math.round(rzpPaymentsFor(s, invId).reduce((a, p) => a + p.amount, 0) * 100) / 100; }
function rzpActiveLink(s, invId) {
  return (s.payLinks || []).filter(l => l.invoice_id === invId && (l.status === 'created' || l.status === 'partially_paid'))
    .sort((a, b) => String(b.created_at).localeCompare(String(a.created_at)))[0] || null;
}

async function rzpCall(body) {
  const { data, error } = await Cloud.client.functions.invoke('razorpay', { body });
  if (error) {
    let msg = error.message;
    try { const j = await error.context.json(); if (j && j.error) msg = j.error; } catch (e) {}
    if (/not found|404/i.test(msg)) msg = 'The razorpay function isn\u2019t set up in Supabase yet.';
    throw new Error(msg);
  }
  if (data && data.error) throw new Error(data.error);
  return data;
}

function PayLinkPanel({ inv, s }) {
  const cs = useCloud();
  const links = (s.payLinks || []).filter(l => l.invoice_id === inv.id).sort((a, b) => String(b.created_at).localeCompare(String(a.created_at)));
  const active = links.find(l => l.status === 'created' || l.status === 'partially_paid');
  const [amt, setAmt] = React.useState('');
  const [partial, setPartial] = React.useState(false);
  const [busy, setBusy] = React.useState('');
  const [err, setErr] = React.useState('');
  const synced = React.useRef(false);

  // Webhooks do the real work; this is a quiet catch-up whenever the invoice
  // is opened, so a missed webhook still lands.
  React.useEffect(() => {
    if (!active || synced.current || !cs.canWrite) return;
    synced.current = true;
    rzpCall({ action: 'sync', ids: [active.id] }).then(() => CloudSync.refresh(), () => {});
  }, [active && active.id, cs.canWrite]);

  async function run(label, body, after) {
    setErr(''); setBusy(label);
    try { const d = await rzpCall(body); await CloudSync.refresh(); if (after) after(d); }
    catch (e) { setErr(e.message); }
    setBusy('');
  }
  function create() {
    const amount = Number(amt || inv.due);
    if (!(amount >= 1)) { setErr('Enter an amount.'); return; }
    if (amount > inv.due + 1 && !confirm('That is more than the ' + fmtINR(inv.due) + ' due. Create it anyway?')) return;
    run('create', { action: 'create', invoice_id: inv.id, amount, partial }, () => setAmt(''));
  }
  function copy(url) {
    (navigator.clipboard ? navigator.clipboard.writeText(url) : Promise.reject()).then(() => alert('Payment link copied:\n' + url), () => prompt('Copy this link:', url));
  }
  function whatsapp(l) {
    const text = [(inv.customer_name ? 'Dear ' + String(inv.customer_name).split(/\s+/)[0] + ',' : ''), 'Here is the secure payment link for invoice ' + (inv.number || '') + (inv.title ? ' · ' + inv.title : '') + '.', 'Amount ' + invINR(l.amount - (Number(l.amount_paid) || 0)), '', l.short_url].filter(x => x !== '').join('\n');
    window.open('https://wa.me/?text=' + encodeURIComponent(text), '_blank');
  }

  const paidHere = rzpPaidFor(s, inv.id);
  return (
    <div className="panel-section">
      <label className="field-label">Razorpay link</label>
      {!cs.session && <div className="muted" style={{ fontSize: 10.5 }}>Sign in to the cloud to create payment links.</div>}
      {cs.session && inv.status === 'draft' && <div className="muted" style={{ fontSize: 10.5 }}>Mark the invoice as sent first.</div>}

      {active && (
        <div className="inv-paybox">
          <div className="row gap-2" style={{ justifyContent: 'space-between', alignItems: 'center' }}>
            <span className={'tag ' + (active.status === 'partially_paid' ? 'tag-transfer' : 'tag-empty')}>{active.status === 'partially_paid' ? 'part paid' : 'awaiting payment'}</span>
            <b className="num">{fmtINR(active.amount)}</b>
          </div>
          <div className="mono" style={{ fontSize: 10.5, marginTop: 8, wordBreak: 'break-all' }}>{active.short_url}</div>
          {Number(active.amount_paid) > 0 && <div className="muted" style={{ fontSize: 10.5, marginTop: 4 }}>{fmtINR(active.amount_paid)} received so far</div>}
          <div className="row gap-2" style={{ marginTop: 8, flexWrap: 'wrap' }}>
            <button className="btn btn-sm" onClick={() => copy(active.short_url)}>Copy</button>
            <button className="btn btn-sm" onClick={() => whatsapp(active)}>WhatsApp</button>
            <button className="btn btn-sm btn-ghost" disabled={!!busy} onClick={() => run('sync', { action: 'sync', ids: [active.id] })}>{busy === 'sync' ? 'Checking…' : 'Check status'}</button>
            <button className="btn btn-sm btn-ghost" disabled={!!busy} onClick={() => { if (confirm('Cancel this payment link? The client won\u2019t be able to pay with it.')) run('cancel', { action: 'cancel', id: active.id }); }}>{busy === 'cancel' ? 'Cancelling…' : 'Cancel link'}</button>
          </div>
        </div>
      )}

      {!active && cs.session && inv.status !== 'draft' && inv.due > 1 && (
        <div style={{ display: 'grid', gap: 8 }}>
          <div className="row gap-2">
            <input className="input num" type="number" placeholder={String(Math.round(inv.due * 100) / 100)} value={amt} onChange={e => setAmt(e.target.value)} />
            <button className="btn btn-primary" disabled={!!busy} onClick={create} style={{ whiteSpace: 'nowrap' }}>{busy === 'create' ? 'Creating…' : 'Create link'}</button>
          </div>
          <div className="pills">
            <div className={'pill ' + (!amt ? 'active' : '')} onClick={() => setAmt('')}>Balance {fmtINR(inv.due)}</div>
            {(inv.schedule || []).filter(m => Number(m.amount) > 0).slice(0, 3).map((m, i) => <div key={i} className={'pill ' + (Number(amt) === Number(m.amount) ? 'active' : '')} onClick={() => setAmt(String(m.amount))}>{m.label || 'Instalment ' + (i + 1)} {fmtINR(m.amount)}</div>)}
          </div>
          <label className="row gap-2" style={{ alignItems: 'center', fontSize: 11, cursor: 'pointer' }}>
            <input type="checkbox" checked={partial} onChange={e => setPartial(e.target.checked)} /> Let the client pay part of it
          </label>
          <div className="muted" style={{ fontSize: 10, lineHeight: 1.5 }}>A link for this exact amount. When the client pays, the invoice updates itself — no statement matching. The Razorpay settlement in your bank is the ledger entry; don't link it to the invoice as well.</div>
        </div>
      )}
      {!active && inv.due <= 1 && paidHere > 0 && <div className="muted" style={{ fontSize: 10.5 }}>Paid {fmtINR(paidHere)} through Razorpay.</div>}
      {err && <div className="t-debit" style={{ fontSize: 11.5, marginTop: 6 }}>{err}</div>}

      {links.filter(l => l !== active).length > 0 && (
        <div style={{ marginTop: 8 }}>
          {links.filter(l => l !== active).slice(0, 4).map(l => (
            <div key={l.id} className="row gap-2" style={{ fontSize: 10.5, justifyContent: 'space-between', padding: '3px 0' }}>
              <span className="muted">{fmtDate(String(l.created_at).slice(0, 10))} · {l.status.replace('_', ' ')}</span>
              <span className="num">{fmtINR(l.amount)}</span>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

Object.assign(window, { rzpPaymentsFor, rzpPaidFor, rzpActiveLink, rzpCall, PayLinkPanel });
