import { useState, useEffect } from 'react';

const MONTH_NAMES = [
  'January', 'February', 'March', 'April', 'May', 'June',
  'July', 'August', 'September', 'October', 'November', 'December',
];

function ordinal(n) {
  const s = ['th', 'st', 'nd', 'rd'];
  const v = n % 100;
  return n + (s[(v - 20) % 10] || s[v] || s[0]);
}

function formatCurrency(value) {
  const num = parseFloat(value) || 0;
  return '$' + num.toLocaleString('en-US', { minimumFractionDigits: 2, maximumFractionDigits: 2 });
}

function formatPayDate(dateStr) {
  const [year, month, day] = dateStr.split('-').map(Number);
  return `${MONTH_NAMES[month - 1]} ${day}, ${year}`;
}

function todayISO() {
  return new Date().toISOString().slice(0, 10);
}

export { ordinal, formatCurrency, formatPayDate };

// ─── PaycheckColumn ───────────────────────────────────────────────────────────

function PaycheckColumn({ paycheck, onBillPaidToggle, categories, onOtePaidToggle, onOteDelete, onOteAdd, onGenerate, onAmountSave, onBillAmountSave, onFinancingPaidToggle }) {
  const [newOteName, setNewOteName] = useState('');
  const [newOteAmount, setNewOteAmount] = useState('');
  const [actuals, setActuals] = useState([]);
  const [actualsLoading, setActualsLoading] = useState(false);
  const [actualsError, setActualsError] = useState(null);

  const [formCategoryId, setFormCategoryId] = useState('');
  const [formAmount, setFormAmount] = useState('');
  const [formNote, setFormNote] = useState('');
  const [formDate, setFormDate] = useState(todayISO());
  const [formSubmitting, setFormSubmitting] = useState(false);
  const [formError, setFormError] = useState(null);

  // Inline bill amount editing (for variable bills)
  const [editingBillAmount, setEditingBillAmount] = useState(null); // bill_id
  const [billAmountDraft, setBillAmountDraft] = useState('');
  const [billAmountSaving, setBillAmountSaving] = useState(false);

  async function saveBillAmount(bill) {
    setBillAmountSaving(true);
    try {
      await onBillAmountSave(bill.paycheck_bill_id, bill.bill_id, paycheck.paycheck_number, parseFloat(billAmountDraft) || 0);
      setEditingBillAmount(null);
    } catch (err) {
      alert(`Failed to save amount: ${err.message}`);
    } finally {
      setBillAmountSaving(false);
    }
  }

  // Inline gross/net editing
  const [editingAmounts, setEditingAmounts] = useState(false);
  const [editGross, setEditGross] = useState('');
  const [editNet, setEditNet] = useState('');
  const [amountSaving, setAmountSaving] = useState(false);
  const [amountError, setAmountError] = useState(null);

  useEffect(() => {
    if (!paycheck?.id) { setActuals([]); return; }
    loadActuals(paycheck.id);
  }, [paycheck?.id]);

  async function loadActuals(paycheckId) {
    setActualsLoading(true);
    setActualsError(null);
    try {
      const res = await fetch(`/api/actuals?paycheck_id=${paycheckId}`);
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      setActuals(await res.json());
    } catch (err) {
      setActualsError(err.message);
    } finally {
      setActualsLoading(false);
    }
  }

  async function handleAddActual(e) {
    e.preventDefault();
    if (!formAmount) { setFormError('Amount is required'); return; }
    setFormSubmitting(true);
    setFormError(null);
    try {
      // Lazy generate if this is a virtual paycheck
      let paycheckId = paycheck.id;
      if (!paycheckId) {
        const generated = await onGenerate();
        paycheckId = generated.find(p => p.paycheck_number === paycheck.paycheck_number).id;
      }

      const res = await fetch('/api/actuals', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          paycheck_id: paycheckId,
          category_id: formCategoryId || null,
          amount: parseFloat(formAmount),
          note: formNote || null,
          date: formDate || todayISO(),
        }),
      });
      if (!res.ok) {
        const body = await res.json();
        throw new Error(body.error || `Server error: ${res.status}`);
      }
      await loadActuals(paycheckId);
      setFormCategoryId('');
      setFormAmount('');
      setFormNote('');
      setFormDate(todayISO());
    } catch (err) {
      setFormError(err.message);
    } finally {
      setFormSubmitting(false);
    }
  }

  async function handleDeleteActual(id) {
    try {
      const res = await fetch(`/api/actuals/${id}`, { method: 'DELETE' });
      if (!res.ok) {
        const body = await res.json();
        throw new Error(body.error || `Server error: ${res.status}`);
      }
      setActuals(prev => prev.filter(a => a.id !== id));
    } catch (err) {
      alert(`Failed to delete actual: ${err.message}`);
    }
  }

  function openAmountEdit() {
    setEditGross(parseFloat(paycheck.gross) || '');
    setEditNet(parseFloat(paycheck.net) || '');
    setAmountError(null);
    setEditingAmounts(true);
  }

  async function saveAmounts(e) {
    e.preventDefault();
    setAmountSaving(true);
    setAmountError(null);
    try {
      await onAmountSave(paycheck.paycheck_number, parseFloat(editGross) || 0, parseFloat(editNet) || 0);
      setEditingAmounts(false);
    } catch (err) {
      setAmountError(err.message);
    } finally {
      setAmountSaving(false);
    }
  }

  if (!paycheck) {
    return (
      <div className="paycheck-card">
        <div className="paycheck-card__body">
          <p className="empty-state">No data</p>
        </div>
      </div>
    );
  }

  const isVirtual = paycheck.id === null;
  const net = parseFloat(paycheck.net) || 0;
  const billsTotal = paycheck.bills.reduce((sum, b) => sum + (parseFloat(b.effective_amount) || 0), 0);
  const otesTotal = paycheck.one_time_expenses.reduce((sum, e) => sum + (parseFloat(e.amount) || 0), 0);
  const actualsTotal = actuals.reduce((sum, a) => sum + (parseFloat(a.amount) || 0), 0);
  const financingTotal = (paycheck.financing || []).reduce((sum, f) => sum + (parseFloat(f.amount) || 0), 0);
  const remaining = net - billsTotal - otesTotal - actualsTotal - financingTotal;

  return (
    <div className="paycheck-card">
      <div className="paycheck-card__header">
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start' }}>
          <div>
            <div className="paycheck-card__number">
              Paycheck {paycheck.paycheck_number}
              {isVirtual && (
                <span style={{
                  marginLeft: '0.5rem',
                  fontSize: '0.65rem',
                  background: 'var(--accent-subtle)',
                  color: 'var(--accent)',
                  padding: '0.1rem 0.4rem',
                  borderRadius: '999px',
                  border: '1px solid var(--accent)',
                  verticalAlign: 'middle',
                }}>preview</span>
              )}
            </div>
            <div className="paycheck-card__date">{formatPayDate(paycheck.pay_date)}</div>
          </div>
        </div>

        {editingAmounts ? (
          <form onSubmit={saveAmounts} style={{ marginTop: '0.5rem' }}>
            <div style={{ display: 'flex', gap: '0.5rem', flexWrap: 'wrap', alignItems: 'center' }}>
              <div className="form-group" style={{ flex: '1 1 120px' }}>
                <label className="form-label">Gross</label>
                <input type="number" min="0" step="0.01" value={editGross}
                  onChange={e => setEditGross(e.target.value)} className="form-input" />
              </div>
              <div className="form-group" style={{ flex: '1 1 120px' }}>
                <label className="form-label">Net</label>
                <input type="number" min="0" step="0.01" value={editNet}
                  onChange={e => setEditNet(e.target.value)} className="form-input" />
              </div>
            </div>
            {amountError && <div className="form-error">{amountError}</div>}
            <div style={{ display: 'flex', gap: '0.4rem', marginTop: '0.5rem' }}>
              <button type="submit" className="btn btn-sm btn-primary" disabled={amountSaving}>
                {amountSaving ? 'Saving…' : 'Save'}
              </button>
              <button type="button" className="btn btn-sm" onClick={() => setEditingAmounts(false)}>
                Cancel
              </button>
            </div>
          </form>
        ) : (
          <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginTop: '0.35rem' }}>
            <div className="paycheck-card__amounts">
              <span>Gross: <strong>{formatCurrency(paycheck.gross)}</strong></span>
              <span>Net: <strong>{formatCurrency(paycheck.net)}</strong></span>
            </div>
            <button
              className="btn-icon"
              onClick={openAmountEdit}
              title="Edit gross / net"
              style={{ fontSize: '0.85rem', color: 'var(--text-faint)', flexShrink: 0 }}
            >
              ✎
            </button>
          </div>
        )}
      </div>

      <div className="paycheck-card__body">
        {/* Bills */}
        <div className="mb-2">
          <div className="section-title">Bills</div>
          {paycheck.bills.length === 0 ? (
            <p className="empty-state">(none)</p>
          ) : (
            paycheck.bills.map((bill) => (
              <div key={bill.bill_id} className="bill-row" style={{ opacity: bill.paid ? 0.6 : 1 }}>
                <input
                  type="checkbox"
                  checked={!!bill.paid}
                  onChange={() => onBillPaidToggle(bill.paycheck_bill_id, !bill.paid, bill.bill_id, paycheck.paycheck_number)}
                  className="bill-row__check"
                />
                <div className="bill-row__info">
                  <div className={`bill-row__name${bill.paid ? ' paid' : ''}`}>
                    <span>{bill.name}</span>
                    {bill.variable_amount && editingBillAmount === bill.bill_id ? (
                      <span style={{ display: 'flex', alignItems: 'center', gap: '0.25rem' }}>
                        <input
                          type="number"
                          min="0"
                          step="0.01"
                          value={billAmountDraft}
                          onChange={e => setBillAmountDraft(e.target.value)}
                          className="form-input"
                          style={{ width: '90px', padding: '0.2rem 0.35rem', fontSize: '0.8rem' }}
                          autoFocus
                          onKeyDown={e => {
                            if (e.key === 'Enter') saveBillAmount(bill);
                            if (e.key === 'Escape') setEditingBillAmount(null);
                          }}
                        />
                        <button className="btn btn-sm btn-primary" disabled={billAmountSaving}
                          onClick={() => saveBillAmount(bill)} style={{ padding: '0.2rem 0.4rem', fontSize: '0.75rem' }}>
                          ✓
                        </button>
                        <button className="btn btn-sm" onClick={() => setEditingBillAmount(null)}
                          style={{ padding: '0.2rem 0.4rem', fontSize: '0.75rem' }}>✕</button>
                      </span>
                    ) : (
                      <span style={{ display: 'flex', alignItems: 'center', gap: '0.25rem' }}>
                        <span className="bill-row__amount">
                          {bill.variable_amount && !bill.amount_override
                            ? <span className="text-faint" style={{ fontSize: '0.8rem' }}>enter amount</span>
                            : formatCurrency(bill.effective_amount)}
                        </span>
                        {bill.variable_amount && !bill.paid && (
                          <button className="btn-icon" style={{ fontSize: '0.8rem', color: 'var(--text-faint)' }}
                            onClick={() => { setBillAmountDraft(bill.amount_override ?? bill.amount ?? ''); setEditingBillAmount(bill.bill_id); }}
                            title="Set this month's amount">✎</button>
                        )}
                      </span>
                    )}
                  </div>
                  <div className="bill-row__meta">
                    <span>due {ordinal(bill.due_day)}</span>
                    {bill.variable_amount && <span className="badge badge-category">variable</span>}
                    {bill.category && <span className="badge badge-category">{bill.category}</span>}
                  </div>
                </div>
              </div>
            ))
          )}
        </div>

        {/* One-time expenses */}
        <div className="mb-2">
          <div className="section-title">One-time Expenses</div>
          {paycheck.one_time_expenses.length === 0 ? (
            <p className="empty-state">(none)</p>
          ) : (
            paycheck.one_time_expenses.map((ote) => (
              <div key={ote.id} className="ote-row" style={{ opacity: ote.paid ? 0.6 : 1 }}>
                <input
                  type="checkbox"
                  checked={!!ote.paid}
                  onChange={() => onOtePaidToggle(ote.id, !ote.paid)}
                  className="ote-row__check"
                />
                <span className={`ote-row__name${ote.paid ? ' paid' : ''}`}>{ote.name}</span>
                <span className="ote-row__amount">{formatCurrency(ote.amount)}</span>
                <button className="btn-icon" onClick={() => onOteDelete(ote.id)} title="Remove">&times;</button>
              </div>
            ))
          )}
          <div className="inline-add-form">
            <input type="text" placeholder="Name" value={newOteName}
              onChange={(e) => setNewOteName(e.target.value)} className="form-input" />
            <input type="number" placeholder="Amount" value={newOteAmount}
              onChange={(e) => setNewOteAmount(e.target.value)} min="0" step="0.01"
              className="form-input" style={{ maxWidth: '100px' }} />
            <button className="btn btn-sm btn-primary" onClick={() => {
              if (!newOteName.trim() || !newOteAmount) return;
              onOteAdd(paycheck.paycheck_number, newOteName.trim(), parseFloat(newOteAmount));
              setNewOteName('');
              setNewOteAmount('');
            }}>
              Add
            </button>
          </div>
        </div>

        {/* Variable spending */}
        <div className="mb-2">
          <div className="section-title">Variable Spending</div>
          {actualsLoading && <p className="empty-state">Loading…</p>}
          {actualsError && <div className="alert alert-error">Error: {actualsError}</div>}
          {!actualsLoading && actuals.length === 0 && <p className="empty-state">(none)</p>}

          {actuals.map((actual) => (
            <div key={actual.id} className="actual-row">
              <div className="actual-row__main">
                <span className="actual-row__category">
                  {actual.category_name || <em className="text-faint">Uncategorized</em>}
                </span>
                <div style={{ display: 'flex', alignItems: 'center', gap: '0.25rem' }}>
                  <span className="actual-row__amount">{formatCurrency(actual.amount)}</span>
                  <button className="btn-icon" onClick={() => handleDeleteActual(actual.id)} title="Remove">&times;</button>
                </div>
              </div>
              <div className="actual-row__meta">
                {actual.note && <span className="actual-row__note">{actual.note}</span>}
                <span>{actual.date}</span>
              </div>
            </div>
          ))}

          <form onSubmit={handleAddActual} className="form-rows">
            <div className="form-row">
              <select value={formCategoryId} onChange={e => setFormCategoryId(e.target.value)} className="form-select">
                <option value="">— Category —</option>
                {categories.map(cat => (
                  <option key={cat.id} value={cat.id}>{cat.name}</option>
                ))}
              </select>
              <input type="number" placeholder="Amount" value={formAmount}
                onChange={e => setFormAmount(e.target.value)} step="0.01" min="0"
                className="form-input" style={{ maxWidth: '110px' }} required />
            </div>
            <div className="form-row">
              <input type="text" placeholder="Note (optional)" value={formNote}
                onChange={e => setFormNote(e.target.value)} className="form-input" />
              <input type="date" value={formDate} onChange={e => setFormDate(e.target.value)}
                className="form-input" style={{ maxWidth: '140px' }} />
              <button type="submit" disabled={formSubmitting} className="btn btn-sm btn-primary" style={{ flexShrink: 0 }}>
                Add
              </button>
            </div>
            {formError && <div className="form-error">{formError}</div>}
          </form>
        </div>

        {/* Financing */}
        {paycheck.financing && paycheck.financing.length > 0 && (
          <div className="mb-2">
            <div className="section-title">Financing</div>
            {paycheck.financing.map((fp) => (
              <div key={fp.plan_id} className="bill-row" style={{ opacity: fp.paid ? 0.6 : 1 }}>
                <input
                  type="checkbox"
                  checked={!!fp.paid}
                  onChange={() => onFinancingPaidToggle(fp.financing_payment_id, !fp.paid, fp.plan_id, paycheck.paycheck_number)}
                  className="bill-row__check"
                  disabled={!fp.financing_payment_id}
                />
                <div className="bill-row__info">
                  <div className={`bill-row__name${fp.paid ? ' paid' : ''}`}>
                    <span style={{ display: 'flex', alignItems: 'center', gap: '0.375rem' }}>
                      {fp.name}
                      {fp.overdue && (
                        <span className="badge" style={{ fontSize: '0.65rem', background: 'var(--danger-bg)', color: 'var(--danger)', border: '1px solid var(--danger)' }}>
                          overdue
                        </span>
                      )}
                    </span>
                    <span className="bill-row__amount">{formatCurrency(fp.amount)}</span>
                  </div>
                  <div className="bill-row__meta">
                    {fp.total_amount != null && (
                      <span>
                        {formatCurrency(fp.paid_total ?? 0)} / {formatCurrency(fp.total_amount)} paid
                      </span>
                    )}
                    <span>due {new Date(fp.due_date).toLocaleDateString('en-US', { month: 'short', year: 'numeric', timeZone: 'UTC' })}</span>
                  </div>
                </div>
              </div>
            ))}
          </div>
        )}

        {/* Remaining */}
        <div className="remaining-row">
          <span className="remaining-row__label">Remaining</span>
          <span className={`remaining-row__amount ${remaining >= 0 ? 'positive' : 'negative'}`}>
            {formatCurrency(remaining)}
          </span>
        </div>
      </div>
    </div>
  );
}

// ─── PaycheckView ─────────────────────────────────────────────────────────────

function PaycheckView() {
  const now = new Date();
  const [year, setYear] = useState(now.getFullYear());
  const [month, setMonth] = useState(now.getMonth() + 1);
  const [paychecks, setPaychecks] = useState([]);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [categories, setCategories] = useState([]);
  const [regenerating, setRegenerating] = useState(false);

  useEffect(() => { loadPaychecks(year, month); }, [year, month]);
  useEffect(() => { loadCategories(); }, []);

  async function loadPaychecks(y, m) {
    setLoading(true);
    setError(null);
    try {
      const res = await fetch(`/api/paychecks?year=${y}&month=${m}`);
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      setPaychecks(await res.json());
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  async function loadCategories() {
    try {
      const res = await fetch('/api/expense-categories');
      if (!res.ok) return;
      setCategories(await res.json());
    } catch { /* silent */ }
  }

  // Generates (or regenerates) paychecks for the current month, updates state,
  // and returns the new paychecks array.
  async function generateMonth() {
    const res = await fetch(`/api/paychecks/generate?year=${year}&month=${month}`, { method: 'POST' });
    if (!res.ok) throw new Error(`Server error: ${res.status}`);
    const data = await res.json();
    setPaychecks(data);
    return data;
  }

  async function handleRegenerate() {
    setRegenerating(true);
    try {
      await generateMonth();
    } catch (err) {
      alert(`Failed to regenerate: ${err.message}`);
    } finally {
      setRegenerating(false);
    }
  }

  function prevMonth() {
    if (month === 1) { setYear(y => y - 1); setMonth(12); } else { setMonth(m => m - 1); }
  }

  function nextMonth() {
    if (month === 12) { setYear(y => y + 1); setMonth(1); } else { setMonth(m => m + 1); }
  }

  // Saves gross/net for a paycheck. If virtual, generates first then patches.
  async function handleAmountSave(paycheckNumber, gross, net) {
    let pc = paychecks.find(p => p.paycheck_number === paycheckNumber);

    if (!pc.id) {
      const generated = await generateMonth();
      pc = generated.find(p => p.paycheck_number === paycheckNumber);
    }

    const res = await fetch(`/api/paychecks/${pc.id}`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ gross, net }),
    });
    if (!res.ok) {
      const body = await res.json();
      throw new Error(body.error || `Server error: ${res.status}`);
    }
    const updated = await res.json();
    setPaychecks(prev => prev.map(p =>
      p.paycheck_number === paycheckNumber
        ? { ...p, id: updated.id, gross: updated.gross, net: updated.net }
        : p
    ));
  }

  async function handleFinancingPaidToggle(financingPaymentId, paid, planId, paycheckNumber) {
    let realId = financingPaymentId;

    // If virtual paycheck, generate first to get real financing_payment_id
    if (!realId) {
      const generated = await generateMonth();
      const pc = generated.find(p => p.paycheck_number === paycheckNumber);
      const fp = pc.financing.find(f => f.plan_id === planId);
      realId = fp?.financing_payment_id;
    }

    if (!realId) {
      alert('Could not find payment record — try refreshing.');
      return;
    }

    try {
      const res = await fetch(`/api/financing-payments/${realId}/paid`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ paid }),
      });
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      const result = await res.json();
      if (result.plan_closed) {
        // Plan paid off — reload to update all state
        await loadPaychecks(year, month);
      } else {
        // Update local financing state
        setPaychecks(prev => prev.map(pc => ({
          ...pc,
          financing: (pc.financing || []).map(f =>
            f.financing_payment_id === realId
              ? { ...f, paid: result.paid, paid_at: result.paid_at }
              : f
          ),
        })));
      }
    } catch (err) {
      alert(`Failed to update payment: ${err.message}`);
    }
  }

  async function handleBillAmountSave(paycheckBillId, billId, paycheckNumber, amount) {
    let realPaycheckBillId = paycheckBillId;

    if (!realPaycheckBillId) {
      const generated = await generateMonth();
      const pc = generated.find(p => p.paycheck_number === paycheckNumber);
      realPaycheckBillId = pc.bills.find(b => b.bill_id === billId).paycheck_bill_id;
    }

    const res = await fetch(`/api/paycheck-bills/${realPaycheckBillId}/amount`, {
      method: 'PATCH',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ amount }),
    });
    if (!res.ok) {
      const body = await res.json();
      throw new Error(body.error || `Server error: ${res.status}`);
    }
    // Reflect the new override in local state
    setPaychecks(prev => prev.map(pc => ({
      ...pc,
      bills: pc.bills.map(b =>
        b.paycheck_bill_id === realPaycheckBillId
          ? { ...b, amount_override: amount, effective_amount: amount }
          : b
      ),
    })));
  }

  async function handleBillPaidToggle(paycheckBillId, paid, billId, paycheckNumber) {
    let realPaycheckBillId = paycheckBillId;

    if (!realPaycheckBillId) {
      // Virtual paycheck — generate first, then find the real paycheck_bill_id
      const generated = await generateMonth();
      const pc = generated.find(p => p.paycheck_number === paycheckNumber);
      const bill = pc.bills.find(b => b.bill_id === billId);
      realPaycheckBillId = bill.paycheck_bill_id;
    }

    // Optimistic update
    setPaychecks(prev => prev.map(pc => ({
      ...pc,
      bills: pc.bills.map(b =>
        b.paycheck_bill_id === realPaycheckBillId
          ? { ...b, paid, paid_at: paid ? new Date().toISOString() : null }
          : b
      ),
    })));

    try {
      const res = await fetch(`/api/paycheck-bills/${realPaycheckBillId}/paid`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ paid }),
      });
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      const updated = await res.json();
      setPaychecks(prev => prev.map(pc => ({
        ...pc,
        bills: pc.bills.map(b =>
          b.paycheck_bill_id === realPaycheckBillId
            ? { ...b, paid: updated.paid, paid_at: updated.paid_at }
            : b
        ),
      })));
    } catch (err) {
      // Revert on failure
      setPaychecks(prev => prev.map(pc => ({
        ...pc,
        bills: pc.bills.map(b =>
          b.paycheck_bill_id === realPaycheckBillId ? { ...b, paid: !paid } : b
        ),
      })));
      alert(`Failed to update bill: ${err.message}`);
    }
  }

  async function handleOtePaidToggle(oteId, paid) {
    try {
      const res = await fetch(`/api/one-time-expenses/${oteId}/paid`, {
        method: 'PATCH',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ paid }),
      });
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      await loadPaychecks(year, month);
    } catch (err) {
      alert(`Failed to update expense: ${err.message}`);
    }
  }

  async function handleOteDelete(oteId) {
    if (!window.confirm('Remove this expense?')) return;
    try {
      const res = await fetch(`/api/one-time-expenses/${oteId}`, { method: 'DELETE' });
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      await loadPaychecks(year, month);
    } catch (err) {
      alert(`Failed to delete expense: ${err.message}`);
    }
  }

  async function handleOteAdd(paycheckNumber, name, amount) {
    let pc = paychecks.find(p => p.paycheck_number === paycheckNumber);
    let paycheckId = pc?.id;

    if (!paycheckId) {
      const generated = await generateMonth();
      paycheckId = generated.find(p => p.paycheck_number === paycheckNumber).id;
    }

    try {
      const res = await fetch('/api/one-time-expenses', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ paycheck_id: paycheckId, name, amount }),
      });
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      await loadPaychecks(year, month);
    } catch (err) {
      alert(`Failed to add expense: ${err.message}`);
    }
  }

  const pc1 = paychecks.find(p => p.paycheck_number === 1) || null;
  const pc2 = paychecks.find(p => p.paycheck_number === 2) || null;
  const isVirtual = paychecks.length > 0 && paychecks.every(p => p.id === null);

  return (
    <div>
      <div className="period-nav">
        <button className="btn-nav" onClick={prevMonth}>&#8592;</button>
        <span className="period-nav__label">{MONTH_NAMES[month - 1]} {year}</span>
        <button className="btn-nav" onClick={nextMonth}>&#8594;</button>
        <button
          className="btn btn-sm"
          onClick={handleRegenerate}
          disabled={regenerating}
          title="Refresh gross/net from current Settings for this month"
          style={{ marginLeft: '0.5rem' }}
        >
          {regenerating ? 'Refreshing…' : '↺ Refresh amounts'}
        </button>
      </div>

      {isVirtual && (
        <div className="alert" style={{
          background: 'var(--accent-subtle)',
          border: '1px solid var(--accent)',
          color: 'var(--accent)',
          marginBottom: '1rem',
          fontSize: '0.875rem',
        }}>
          Previewing from current settings — no data saved yet for this month.
        </div>
      )}

      {error && <div className="alert alert-error">Error: {error}</div>}

      {loading ? (
        <p className="text-muted">Loading…</p>
      ) : (
        <div className="paycheck-grid">
          <PaycheckColumn
            paycheck={pc1}
            onBillPaidToggle={handleBillPaidToggle}
            onOtePaidToggle={handleOtePaidToggle}
            onOteDelete={handleOteDelete}
            onOteAdd={handleOteAdd}
            categories={categories}
            onGenerate={generateMonth}
            onAmountSave={handleAmountSave}
            onBillAmountSave={handleBillAmountSave}
            onFinancingPaidToggle={handleFinancingPaidToggle}
          />
          <PaycheckColumn
            paycheck={pc2}
            onBillPaidToggle={handleBillPaidToggle}
            onOtePaidToggle={handleOtePaidToggle}
            onOteDelete={handleOteDelete}
            onOteAdd={handleOteAdd}
            categories={categories}
            onGenerate={generateMonth}
            onAmountSave={handleAmountSave}
            onBillAmountSave={handleBillAmountSave}
            onFinancingPaidToggle={handleFinancingPaidToggle}
          />
        </div>
      )}
    </div>
  );
}

export default PaycheckView;
