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) {
  // dateStr is YYYY-MM-DD
  const [year, month, day] = dateStr.split('-').map(Number);
  return `${MONTH_NAMES[month - 1]} ${day}, ${year}`;
}

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

function PaycheckColumn({ paycheck, onBillPaidToggle, categories }) {
  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);

  useEffect(() => {
    if (!paycheck) 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}`);
      const data = await res.json();
      setActuals(data);
    } 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 {
      const res = await fetch('/api/actuals', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          paycheck_id: paycheck.id,
          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}`);
      }
      // Refresh the actuals list
      await loadActuals(paycheck.id);
      // Reset form fields (keep date as today)
      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}`);
    }
  }

  if (!paycheck) {
    return (
      <div style={styles.column}>
        <p style={{ color: '#888' }}>No data</p>
      </div>
    );
  }

  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 remaining = net - billsTotal - otesTotal - actualsTotal;
  const remainingColor = remaining >= 0 ? '#2a7a2a' : '#c0392b';

  return (
    <div style={styles.column}>
      <div style={styles.columnHeader}>
        <h2 style={styles.paycheckTitle}>Paycheck {paycheck.paycheck_number}</h2>
        <div style={styles.payDate}>{formatPayDate(paycheck.pay_date)}</div>
        <div style={styles.payAmounts}>
          <span>Gross: <strong>{formatCurrency(paycheck.gross)}</strong></span>
          <span style={{ marginLeft: '1rem' }}>Net: <strong>{formatCurrency(paycheck.net)}</strong></span>
        </div>
      </div>

      <div style={styles.section}>
        <div style={styles.sectionLabel}>Bills</div>
        <div style={styles.divider} />
        {paycheck.bills.length === 0 ? (
          <div style={styles.emptyNote}>(none)</div>
        ) : (
          paycheck.bills.map((bill) => (
            <div
              key={bill.paycheck_bill_id}
              style={{
                ...styles.billRow,
                opacity: bill.paid ? 0.6 : 1,
              }}
            >
              <input
                type="checkbox"
                checked={!!bill.paid}
                onChange={() => onBillPaidToggle(bill.paycheck_bill_id, !bill.paid)}
                style={styles.checkbox}
              />
              <div style={styles.billDetails}>
                <div style={bill.paid ? styles.billNamePaid : styles.billName}>
                  {bill.name}
                  <span style={styles.billAmount}>{formatCurrency(bill.effective_amount)}</span>
                </div>
                <div style={styles.billMeta}>
                  <span>due {ordinal(bill.due_day)}</span>
                  {bill.category && (
                    <span style={styles.category}>{bill.category}</span>
                  )}
                </div>
              </div>
            </div>
          ))
        )}
      </div>

      <div style={styles.section}>
        <div style={styles.sectionLabel}>One-time expenses</div>
        <div style={styles.divider} />
        {paycheck.one_time_expenses.length === 0 ? (
          <div style={styles.emptyNote}>(none)</div>
        ) : (
          paycheck.one_time_expenses.map((ote) => (
            <div key={ote.id} style={styles.oteRow}>
              <span style={styles.oteName}>{ote.name}</span>
              <span style={styles.oteAmount}>{formatCurrency(ote.amount)}</span>
            </div>
          ))
        )}
      </div>

      <div style={styles.section}>
        <div style={styles.sectionLabel}>Variable Spending</div>
        <div style={styles.divider} />

        {actualsLoading && <div style={styles.emptyNote}>Loading…</div>}
        {actualsError && <div style={styles.actualsError}>Error: {actualsError}</div>}

        {!actualsLoading && actuals.length === 0 && (
          <div style={styles.emptyNote}>(none)</div>
        )}

        {actuals.map((actual) => (
          <div key={actual.id} style={styles.actualRow}>
            <div style={styles.actualMain}>
              <span style={styles.actualCategory}>
                {actual.category_name || <em style={{ color: '#aaa' }}>Uncategorized</em>}
              </span>
              <span style={styles.actualAmount}>{formatCurrency(actual.amount)}</span>
            </div>
            <div style={styles.actualMeta}>
              {actual.note && <span style={styles.actualNote}>{actual.note}</span>}
              <span style={styles.actualDate}>{actual.date}</span>
              <button
                style={styles.deleteButton}
                onClick={() => handleDeleteActual(actual.id)}
                title="Remove"
              >
                &times;
              </button>
            </div>
          </div>
        ))}

        <form onSubmit={handleAddActual} style={styles.actualForm}>
          <div style={styles.actualFormRow}>
            <select
              value={formCategoryId}
              onChange={e => setFormCategoryId(e.target.value)}
              style={styles.formSelect}
            >
              <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"
              style={styles.formInput}
              required
            />
          </div>
          <div style={styles.actualFormRow}>
            <input
              type="text"
              placeholder="Note (optional)"
              value={formNote}
              onChange={e => setFormNote(e.target.value)}
              style={{ ...styles.formInput, flex: 2 }}
            />
            <input
              type="date"
              value={formDate}
              onChange={e => setFormDate(e.target.value)}
              style={styles.formInput}
            />
            <button
              type="submit"
              disabled={formSubmitting}
              style={styles.addButton}
            >
              Add
            </button>
          </div>
          {formError && <div style={styles.formError}>{formError}</div>}
        </form>
      </div>

      <div style={styles.remainingRow}>
        <span style={styles.remainingLabel}>Remaining:</span>
        <span style={{ ...styles.remainingAmount, color: remainingColor }}>
          {formatCurrency(remaining)}
        </span>
      </div>
    </div>
  );
}

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

  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}`);
      const data = await res.json();
      setPaychecks(data);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  }

  async function loadCategories() {
    try {
      const res = await fetch('/api/expense-categories');
      if (!res.ok) throw new Error(`Server error: ${res.status}`);
      const data = await res.json();
      setCategories(data);
    } catch (err) {
      console.error('Failed to load expense categories:', err.message);
    }
  }

  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);
    }
  }

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

    try {
      const res = await fetch(`/api/paycheck-bills/${paycheckBillId}/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();
      // Sync server response
      setPaychecks(prev =>
        prev.map(pc => ({
          ...pc,
          bills: pc.bills.map(b =>
            b.paycheck_bill_id === paycheckBillId
              ? { ...b, paid: updated.paid, paid_at: updated.paid_at }
              : b
          ),
        }))
      );
    } catch (err) {
      // Revert optimistic update on failure
      setPaychecks(prev =>
        prev.map(pc => ({
          ...pc,
          bills: pc.bills.map(b =>
            b.paycheck_bill_id === paycheckBillId
              ? { ...b, paid: !paid }
              : b
          ),
        }))
      );
      alert(`Failed to update bill: ${err.message}`);
    }
  }

  const pc1 = paychecks.find(p => p.paycheck_number === 1) || null;
  const pc2 = paychecks.find(p => p.paycheck_number === 2) || null;

  return (
    <div style={styles.container}>
      <div style={styles.monthNav}>
        <button style={styles.navButton} onClick={prevMonth}>&larr;</button>
        <span style={styles.monthLabel}>{MONTH_NAMES[month - 1]} {year}</span>
        <button style={styles.navButton} onClick={nextMonth}>&rarr;</button>
      </div>

      {error && (
        <div style={styles.errorBanner}>Error: {error}</div>
      )}

      {loading ? (
        <div style={styles.loadingMsg}>Loading...</div>
      ) : (
        <div style={styles.grid}>
          <PaycheckColumn
            paycheck={pc1}
            onBillPaidToggle={handleBillPaidToggle}
            categories={categories}
          />
          <PaycheckColumn
            paycheck={pc2}
            onBillPaidToggle={handleBillPaidToggle}
            categories={categories}
          />
        </div>
      )}
    </div>
  );
}

const styles = {
  container: {
    maxWidth: '960px',
    margin: '0 auto',
  },
  monthNav: {
    display: 'flex',
    alignItems: 'center',
    gap: '1rem',
    marginBottom: '1.25rem',
  },
  navButton: {
    padding: '0.3rem 0.75rem',
    fontSize: '1rem',
    cursor: 'pointer',
    border: '1px solid #bbb',
    borderRadius: '4px',
    background: '#f5f5f5',
  },
  monthLabel: {
    fontSize: '1.25rem',
    fontWeight: '600',
    minWidth: '160px',
    textAlign: 'center',
  },
  errorBanner: {
    background: '#fde8e8',
    border: '1px solid #f5a0a0',
    borderRadius: '4px',
    padding: '0.75rem 1rem',
    marginBottom: '1rem',
    color: '#c0392b',
  },
  loadingMsg: {
    padding: '2rem',
    color: '#888',
  },
  grid: {
    display: 'grid',
    gridTemplateColumns: '1fr 1fr',
    gap: '1.5rem',
    alignItems: 'start',
  },
  column: {
    border: '1px solid #ddd',
    borderRadius: '6px',
    padding: '1rem',
    background: '#fafafa',
  },
  columnHeader: {
    marginBottom: '1rem',
    paddingBottom: '0.75rem',
    borderBottom: '2px solid #eee',
  },
  paycheckTitle: {
    margin: '0 0 0.25rem 0',
    fontSize: '1.1rem',
    fontWeight: '700',
  },
  payDate: {
    color: '#555',
    marginBottom: '0.4rem',
    fontSize: '0.95rem',
  },
  payAmounts: {
    fontSize: '0.95rem',
    color: '#333',
  },
  section: {
    marginBottom: '1rem',
  },
  sectionLabel: {
    fontWeight: '600',
    fontSize: '0.9rem',
    color: '#444',
    marginBottom: '0.25rem',
  },
  divider: {
    borderTop: '1px solid #ddd',
    marginBottom: '0.5rem',
  },
  emptyNote: {
    color: '#aaa',
    fontSize: '0.875rem',
    fontStyle: 'italic',
    paddingLeft: '0.25rem',
  },
  billRow: {
    display: 'flex',
    alignItems: 'flex-start',
    gap: '0.5rem',
    marginBottom: '0.5rem',
  },
  checkbox: {
    marginTop: '3px',
    cursor: 'pointer',
    flexShrink: 0,
  },
  billDetails: {
    flex: 1,
  },
  billName: {
    display: 'flex',
    justifyContent: 'space-between',
    fontWeight: '500',
    fontSize: '0.95rem',
  },
  billNamePaid: {
    display: 'flex',
    justifyContent: 'space-between',
    fontWeight: '500',
    fontSize: '0.95rem',
    textDecoration: 'line-through',
    color: '#999',
  },
  billAmount: {
    fontVariantNumeric: 'tabular-nums',
    marginLeft: '0.5rem',
  },
  billMeta: {
    fontSize: '0.8rem',
    color: '#888',
    display: 'flex',
    gap: '0.5rem',
    marginTop: '1px',
  },
  category: {
    background: '#e8eaf0',
    borderRadius: '3px',
    padding: '0 4px',
    fontSize: '0.75rem',
    color: '#666',
  },
  oteRow: {
    display: 'flex',
    justifyContent: 'space-between',
    fontSize: '0.95rem',
    padding: '0.2rem 0',
  },
  oteName: {
    color: '#333',
  },
  oteAmount: {
    fontVariantNumeric: 'tabular-nums',
    color: '#333',
  },
  // Actuals styles
  actualsError: {
    color: '#c0392b',
    fontSize: '0.85rem',
    marginBottom: '0.4rem',
  },
  actualRow: {
    marginBottom: '0.5rem',
    fontSize: '0.9rem',
  },
  actualMain: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'baseline',
  },
  actualCategory: {
    fontWeight: '500',
    color: '#333',
  },
  actualAmount: {
    fontVariantNumeric: 'tabular-nums',
    color: '#333',
    marginLeft: '0.5rem',
  },
  actualMeta: {
    display: 'flex',
    gap: '0.5rem',
    alignItems: 'center',
    fontSize: '0.8rem',
    color: '#888',
    marginTop: '1px',
  },
  actualNote: {
    fontStyle: 'italic',
    flex: 1,
  },
  actualDate: {
    whiteSpace: 'nowrap',
  },
  deleteButton: {
    background: 'none',
    border: 'none',
    cursor: 'pointer',
    color: '#c0392b',
    fontSize: '1rem',
    lineHeight: '1',
    padding: '0 2px',
    opacity: 0.7,
  },
  actualForm: {
    marginTop: '0.75rem',
    display: 'flex',
    flexDirection: 'column',
    gap: '0.4rem',
  },
  actualFormRow: {
    display: 'flex',
    gap: '0.4rem',
    flexWrap: 'wrap',
  },
  formSelect: {
    flex: 1,
    minWidth: '100px',
    fontSize: '0.85rem',
    padding: '0.3rem 0.4rem',
    border: '1px solid #ccc',
    borderRadius: '4px',
  },
  formInput: {
    flex: 1,
    minWidth: '70px',
    fontSize: '0.85rem',
    padding: '0.3rem 0.4rem',
    border: '1px solid #ccc',
    borderRadius: '4px',
  },
  addButton: {
    padding: '0.3rem 0.75rem',
    fontSize: '0.85rem',
    cursor: 'pointer',
    border: '1px solid #bbb',
    borderRadius: '4px',
    background: '#e8f0e8',
    color: '#2a7a2a',
    fontWeight: '600',
    whiteSpace: 'nowrap',
  },
  formError: {
    color: '#c0392b',
    fontSize: '0.8rem',
  },
  remainingRow: {
    display: 'flex',
    justifyContent: 'space-between',
    alignItems: 'center',
    marginTop: '0.5rem',
    paddingTop: '0.75rem',
    borderTop: '2px solid #ddd',
  },
  remainingLabel: {
    fontWeight: '600',
    fontSize: '1rem',
  },
  remainingAmount: {
    fontWeight: '700',
    fontSize: '1.1rem',
    fontVariantNumeric: 'tabular-nums',
  },
};

export default PaycheckView;
