// daygig-accounting.js — Accounting / Books: ledger, chart of accounts, journal entry

// ── Profile helpers ───────────────────────────────────────────────────────
  function dgAcctSettings() {
    if (typeof getDaygigSettings === 'function') return getDaygigSettings();
    if (window.DAYGIG_SETTINGS) return window.DAYGIG_SETTINGS;
    if (typeof settings === 'object' && settings) return settings;
    return {};
  }

  function acctIsPersonalMode() {
    const s = dgAcctSettings();
    return (s.user_profile || s.profile || '').toLowerCase() === 'personal';
  }

  function applyAccountingProfileUi() {
    const personal = acctIsPersonalMode();
    document.querySelectorAll('.acct-tab').forEach(btn => {
      const name = btn.dataset.acct;
      if (personal && name === 'ledger') btn.textContent = 'Transactions';
      if (personal && name === 'expenses') btn.textContent = 'Spending';
      if (personal && name === 'accounts') btn.textContent = 'Categories';
      if (personal && name === 'journal') btn.textContent = 'Manual Entry';
      if (!personal && name === 'ledger') btn.textContent = 'Ledger';
      if (!personal && name === 'expenses') btn.textContent = 'Expenses';
      if (!personal && name === 'accounts') btn.textContent = 'Chart of Accounts';
      if (!personal && name === 'journal') btn.textContent = 'Journal Entry';
    });
    const sub = document.getElementById('acct-sub');
    if (sub && personal) sub.textContent = 'Spending and balance categories';
  }

// ── Accounting tab switcher ───────────────────────────────────────────────
  function acctTab(name) {
    applyAccountingProfileUi();
    document.querySelectorAll('.acct-tab').forEach(b => {
      const active = b.dataset.acct === name;
      b.style.borderBottomColor = active ? 'var(--accent)' : 'transparent';
      b.style.color = active ? 'var(--accent)' : 'var(--text-soft)';
    });
    ['ledger','expenses','accounts','journal','equity','recurring'].forEach(t => {
      const el = document.getElementById('acct-' + t);
      if (el) el.style.display = t === name ? '' : 'none';
    });
    if (name === 'recurring') recInit();
    if (name === 'ledger')   acctLedgerLoad();
    if (name === 'expenses') {
      const expDate = document.getElementById('exp-date');
      if (expDate && !expDate.value) expDate.value = new Date().toISOString().split('T')[0];
      if (typeof loadExpenseAccounts === 'function') loadExpenseAccounts();
      if (typeof loadExpenses === 'function') loadExpenses();
    }
    if (name === 'accounts') accountsLoad();
    if (name === 'journal')  jrnInit();
    if (name === 'equity')   ownerEquityInit();
  }

  // ── Owner draws & contributions ───────────────────────────────────────────
  async function ownerEquityInit() {
    const dateEl = document.getElementById('oe-date');
    if (dateEl && !dateEl.value) dateEl.value = new Date().toISOString().split('T')[0];
    const sel = document.getElementById('oe-account');
    if (sel && !sel.dataset.loaded) {
      try {
        const res = await fetch('/api/accounts');
        const data = await res.json();
        const accts = (Array.isArray(data) ? data : (data.accounts || []))
          .filter(a => a.account_type === 'asset');
        sel.innerHTML = accts.map(a =>
          `<option value="${a.name.replace(/"/g, '&quot;')}">${(a.display_name || a.name)}</option>`).join('');
        sel.dataset.loaded = '1';
      } catch (_) { /* leave empty; user can retry */ }
    }
  }

  async function submitOwnerEquity() {
    const kind = document.getElementById('oe-kind')?.value || 'draw';
    const asset_account = document.getElementById('oe-account')?.value || '';
    const amount = parseFloat(document.getElementById('oe-amount')?.value || '0');
    const date = document.getElementById('oe-date')?.value || '';
    const memo = document.getElementById('oe-memo')?.value || '';
    const msg = document.getElementById('oe-msg');
    const show = (text, ok) => { if (msg) { msg.textContent = text; msg.style.color = ok ? 'var(--accent)' : 'var(--err)'; msg.style.display = 'inline'; } };
    if (!asset_account) { show('Pick a cash/bank account.', false); return; }
    if (!(amount > 0)) { show('Enter an amount above $0.', false); return; }
    try {
      const res = await fetch('/api/owner-equity', {
        method: 'POST', headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ kind, asset_account, amount, date, memo }),
      });
      const data = await res.json();
      if (!data.ok) { show('Failed: ' + (data.error || 'unknown'), false); return; }
      show(`Recorded ${kind} of ${dgMoney(data.amount)}.`, true);
      document.getElementById('oe-amount').value = '';
      document.getElementById('oe-memo').value = '';
      if (typeof loadDashboard === 'function') loadDashboard();
    } catch (e) { show('Failed: ' + e.message, false); }
  }
  if (typeof window !== 'undefined') {
    window.ownerEquityInit = ownerEquityInit;
    window.submitOwnerEquity = submitOwnerEquity;
  }

  // ── Recurring / expected transactions ─────────────────────────────────────
  let _recAccounts = null;
  async function recInit() {
    const due = document.getElementById('rec-next-due');
    if (due && !due.value) due.value = new Date().toISOString().split('T')[0];
    if (!_recAccounts) {
      try {
        const res = await fetch('/api/accounts');
        const data = await res.json();
        _recAccounts = (Array.isArray(data) ? data : (data.accounts || []));
      } catch (_) { _recAccounts = []; }
    }
    // Payment (asset) accounts.
    const pay = document.getElementById('rec-payment');
    if (pay) pay.innerHTML = _recAccounts.filter(a => a.account_type === 'asset')
      .map(a => `<option value="${a.id}">${a.display_name || a.name}</option>`).join('');
    recLoadCategoryOptions();
    recList();
  }
  function recLoadCategoryOptions() {
    const kind = document.getElementById('rec-kind')?.value || 'expense';
    const want = kind === 'income' ? ['income'] : ['expense', 'cogs'];
    const sel = document.getElementById('rec-account');
    if (sel && _recAccounts) sel.innerHTML = _recAccounts.filter(a => want.includes(a.account_type))
      .map(a => `<option value="${a.id}">${a.display_name || a.name}</option>`).join('');
  }
  async function recSave() {
    const payload = {
      name: document.getElementById('rec-name')?.value || '',
      kind: document.getElementById('rec-kind')?.value || 'expense',
      account_id: parseInt(document.getElementById('rec-account')?.value || '0', 10),
      payment_account_id: parseInt(document.getElementById('rec-payment')?.value || '0', 10),
      amount: parseFloat(document.getElementById('rec-amount')?.value || '0'),
      cadence: document.getElementById('rec-cadence')?.value || 'monthly',
      next_due: document.getElementById('rec-next-due')?.value || '',
      vendor: document.getElementById('rec-vendor')?.value || '',
    };
    const msg = document.getElementById('rec-msg');
    const show = (t, ok) => { if (msg) { msg.textContent = t; msg.style.color = ok ? 'var(--accent)' : 'var(--err)'; msg.style.display = 'inline'; } };
    if (!payload.name) { show('Name is required.', false); return; }
    if (!(payload.amount > 0)) { show('Enter an amount.', false); return; }
    try {
      const res = await fetch('/api/recurring', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) });
      const data = await res.json();
      if (!data.ok) { show('Failed: ' + (data.error || 'unknown'), false); return; }
      show('Added.', true);
      document.getElementById('rec-name').value = '';
      document.getElementById('rec-amount').value = '';
      document.getElementById('rec-vendor').value = '';
      recList();
      if (typeof loadAlerts === 'function') loadAlerts();
    } catch (e) { show('Failed: ' + e.message, false); }
  }
  async function recList() {
    const box = document.getElementById('rec-list');
    if (!box) return;
    box.textContent = 'Loading…';
    try {
      const res = await fetch('/api/recurring');
      const data = await res.json();
      const items = (data.recurring || []);
      if (!items.length) { box.innerHTML = '<div style="color:var(--text-dim);padding:8px 0;">No recurring items yet.</div>'; return; }
      const esc = (s) => String(s == null ? '' : s).replace(/[&<>]/g, m => ({'&':'&amp;','<':'&lt;','>':'&gt;'}[m]));
      box.innerHTML = `<table style="width:100%;border-collapse:collapse;font-size:12px;">
        <thead><tr style="color:var(--text-dim);border-bottom:1px solid var(--border);">
          <th style="text-align:left;padding:5px 8px;">Name</th><th style="text-align:left;padding:5px 8px;">Type</th>
          <th style="text-align:right;padding:5px 8px;">Amount</th><th style="text-align:left;padding:5px 8px;">Cadence</th>
          <th style="text-align:left;padding:5px 8px;">Next due</th><th style="padding:5px 8px;"></th></tr></thead>
        <tbody>${items.map(r => `<tr style="border-bottom:1px solid var(--border);${r.due_now ? 'background:rgba(184,134,11,.08);' : ''}">
          <td style="padding:5px 8px;">${esc(r.name)}${r.vendor ? ` <span style="color:var(--text-dim);">(${esc(r.vendor)})</span>` : ''}</td>
          <td style="padding:5px 8px;color:var(--text-soft);">${esc(r.kind)}</td>
          <td style="padding:5px 8px;text-align:right;">${dgMoney(r.amount)}</td>
          <td style="padding:5px 8px;color:var(--text-soft);">${esc(r.cadence)}</td>
          <td style="padding:5px 8px;">${esc(r.next_due)}${r.due_now ? ' <span style="color:var(--warn,#b8860b);">due</span>' : (r.days_until != null ? ` <span style="color:var(--text-dim);">(${r.days_until}d)</span>` : '')}</td>
          <td style="padding:5px 8px;text-align:right;white-space:nowrap;">
            <button onclick="recPost(${r.id})" style="background:var(--accent-bg);border:1px solid var(--accent-ring);border-radius:5px;color:var(--accent);font-size:11px;padding:3px 8px;cursor:pointer;">Post</button>
            <button onclick="recDelete(${r.id})" style="background:transparent;border:1px solid var(--border);border-radius:5px;color:var(--text-dim);font-size:11px;padding:3px 8px;cursor:pointer;margin-left:4px;">Delete</button>
          </td></tr>`).join('')}</tbody></table>`;
    } catch (e) { box.textContent = 'Error: ' + e.message; }
  }
  async function recPost(id) {
    if (!confirm('Post this occurrence to the ledger? The next due date will advance.')) return;
    try {
      const res = await fetch('/api/recurring/' + id + '/post', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: '{}' });
      const data = await res.json();
      if (!data.ok) { alert('Post failed: ' + (data.error || 'unknown')); return; }
      recList();
      if (typeof loadAlerts === 'function') loadAlerts();
      if (typeof loadDashboard === 'function') loadDashboard();
    } catch (e) { alert('Post failed: ' + e.message); }
  }
  async function recDelete(id) {
    if (!confirm('Delete this recurring template? Posted transactions are not affected.')) return;
    try {
      await fetch('/api/recurring/delete/' + id, { method: 'POST' });
      recList();
      if (typeof loadAlerts === 'function') loadAlerts();
    } catch (e) { alert('Delete failed: ' + e.message); }
  }
  if (typeof window !== 'undefined') {
    window.recInit = recInit; window.recLoadCategoryOptions = recLoadCategoryOptions;
    window.recSave = recSave; window.recList = recList;
    window.recPost = recPost; window.recDelete = recDelete;
  }

  // ── Accounting Ledger ─────────────────────────────────────────────────────
  let _acctLedgerOffset = 0;
  const _acctLedgerLimit = 50;

  async function acctLedgerLoad() {
    _acctLedgerOffset = 0;
    acctLedgerFetch();
  }

  function acctLedgerPage(dir) {
    _acctLedgerOffset = Math.max(0, _acctLedgerOffset + dir * _acctLedgerLimit);
    acctLedgerFetch();
  }

  async function acctLedgerFetch() {
    const tbody = document.getElementById('acct-ledger-body');
    const sub   = document.getElementById('acct-ledger-sub');
    const count = document.getElementById('acct-ledger-count');
    const from  = document.getElementById('acct-ledger-from')?.value || '';
    const to    = document.getElementById('acct-ledger-to')?.value   || '';
    if (!tbody) return;
    tbody.innerHTML = '<tr><td colspan="5" style="padding:32px;text-align:center;color:var(--text-dim);">Loading…</td></tr>';
    try {
      let url = `/api/ledger?limit=${_acctLedgerLimit}&offset=${_acctLedgerOffset}`;
      if (from) url += `&date_from=${from}`;
      if (to)   url += `&date_to=${to}`;
      const res  = await fetch(url);
      const data = await res.json();
      const txns = data.transactions || [];
      const total = data.total || 0;
      const personal = acctIsPersonalMode();
      if (sub) sub.textContent = `${total} ${personal ? 'transaction' : 'ledger transaction'}${total !== 1 ? 's' : ''}`;
      if (count) {
        count.textContent = total
          ? `Showing ${_acctLedgerOffset + 1}–${Math.min(_acctLedgerOffset + _acctLedgerLimit, total)} of ${total}`
          : '';
      }
      const prev = document.getElementById('acct-ledger-prev');
      const next = document.getElementById('acct-ledger-next');
      if (prev) prev.style.display = _acctLedgerOffset > 0 ? '' : 'none';
      if (next) next.style.display = (_acctLedgerOffset + _acctLedgerLimit) < total ? '' : 'none';
      if (!txns.length) {
        tbody.innerHTML = `<tr><td colspan="5" style="padding:32px;text-align:center;color:var(--text-dim);">No ${personal ? 'transactions' : 'transactions posted'} yet.</td></tr>`;
        return;
      }
      tbody.innerHTML = txns.map(t => {
        const accts = (t.postings || []).map(p => p.account_name).filter(Boolean);
        const amounts = (t.postings||[]).map(p => Math.abs(p.amount_cents||0));
        const maxAmt = amounts.length ? Math.max(...amounts) : 0;
        return `<tr style="border-bottom:1px solid var(--border);">
          <td style="padding:7px 10px;font-family:var(--mono);font-size:11px;color:var(--text-soft);white-space:nowrap;">${t.txn_date || ''}</td>
          <td style="padding:7px 10px;font-size:13px;color:var(--text);">${t.description || ''}</td>
          <td style="padding:7px 10px;font-size:11px;color:var(--text-soft);">${accts.slice(0,2).join(' · ')}</td>
          <td style="padding:7px 10px;text-align:right;font-family:var(--mono);font-size:12px;color:var(--text);">${dgMoney(maxAmt/100)}</td>
          <td style="padding:7px 10px;font-family:var(--mono);font-size:10px;color:var(--text-dim);">${t.source_module || '—'}</td>
        </tr>`;
      }).join('');
    } catch(e) { tbody.innerHTML = `<tr><td colspan="5" style="padding:20px;color:var(--err);">Error: ${e.message}</td></tr>`; }
  }

  // ── Chart of Accounts ─────────────────────────────────────────────────────
  async function accountsLoad() {
    applyAccountingProfileUi();
    const tbody = document.getElementById('acct-tbody');
    const sub   = document.getElementById('acct-sub');
    if (!tbody) return;
    tbody.innerHTML = '<tr><td colspan="4" style="padding:32px;text-align:center;color:var(--text-dim);">Loading…</td></tr>';
    try {
      const res  = await fetch('/api/accounts');
      const data = await res.json();
      const accounts = Array.isArray(data) ? data : (data.accounts || []);
      const personal = acctIsPersonalMode();
      if (!accounts.length) {
        tbody.innerHTML = '<tr><td colspan="4" style="padding:32px;text-align:center;color:var(--text-dim);">No accounts found.</td></tr>';
        if (sub) sub.textContent = personal ? 'Spending and balance categories' : 'Chart of accounts';
        return;
      }
      if (sub) sub.textContent = personal ? `${accounts.length} categories/accounts` : `${accounts.length} accounts`;
      const typeColor = {
        asset:'var(--accent)', liability:'var(--err)', equity:'var(--blue)',
        income:'var(--accent)', expense:'var(--warn)', cogs:'var(--warn)'
      };
      const typeLabel = (t) => {
        if (!personal) return t;
        return { asset:'balance', liability:'owed', equity:'net worth', income:'income', expense:'spending', cogs:'spending' }[t] || t;
      };
      tbody.innerHTML = accounts.map(a => {
        const bal = parseFloat(a.balance_cents || 0) / 100;
        const balColor = bal < 0 ? 'var(--err)' : bal > 0 ? 'var(--text)' : 'var(--text-dim)';
        return `<tr style="border-bottom:1px solid var(--border);">
          <td style="padding:7px 10px;font-family:var(--mono);font-size:11px;color:var(--text-soft);">${a.code || a.id}</td>
          <td style="padding:7px 10px;font-size:13px;color:var(--text);font-weight:500;">${a.name}</td>
          <td style="padding:7px 10px;"><span style="font-family:var(--mono);font-size:10px;color:${typeColor[a.account_type]||'var(--text-dim)'};">${typeLabel(a.account_type)}</span></td>
          <td style="padding:7px 10px;text-align:right;font-family:var(--mono);font-size:12px;color:${balColor};">${dgMoney(Math.abs(bal))}</td>
        </tr>`;
      }).join('');
    } catch(e) { tbody.innerHTML = `<tr><td colspan="4" style="padding:20px;color:var(--err);">Error: ${e.message}</td></tr>`; }
  }

  // ── Journal Entry ─────────────────────────────────────────────────────────
  let _jrnAccounts = [];
  let _jrnPostings = [];

  async function jrnInit() {
    applyAccountingProfileUi();
    // Set today's date
    const d = document.getElementById('jrn-date');
    if (d && !d.value) d.value = new Date().toISOString().slice(0,10);
    // Load accounts for selects if not loaded
    if (!_jrnAccounts.length) {
      try {
        const res  = await fetch('/api/accounts');
        const data = await res.json();
        _jrnAccounts = Array.isArray(data) ? data : (data.accounts || []);
      } catch(e) { console.warn('Could not load accounts for journal', e); }
    }
    if (!_jrnPostings.length) jrnReset();
  }

  function jrnReset() {
    _jrnPostings = [
      { account_id: '', amount: '', direction: 'debit' },
      { account_id: '', amount: '', direction: 'credit' },
    ];
    const desc = document.getElementById('jrn-desc');
    const ref = document.getElementById('jrn-ref');
    if (desc) desc.value = '';
    if (ref) ref.value  = '';
    const msg = document.getElementById('jrn-msg');
    if (msg) { msg.style.display = 'none'; msg.textContent = ''; }
    jrnRender();
  }

  function jrnRender() {
    const container = document.getElementById('jrn-postings');
    if (!container) return;
    container.innerHTML = _jrnPostings.map((p, i) => {
      const opts = _jrnAccounts.map(a =>
        `<option value="${a.id}" ${a.id == p.account_id ? 'selected' : ''}>${a.code ? a.code+' — ' : ''}${a.name}</option>`
      ).join('');
      return `<div style="display:grid;grid-template-columns:1fr 140px 130px 36px;gap:8px;align-items:center;margin-bottom:8px;">
        <select onchange="jrnUpdatePosting(${i},'account_id',this.value)"
          style="background:var(--surface2);border:1px solid var(--border);border-radius:7px;color:var(--text);font-size:12px;padding:7px 10px;outline:none;">
          <option value="">— Select account —</option>${opts}
        </select>
        <input type="number" min="0" step="0.01" placeholder="0.00"
          value="${p.amount}"
          onchange="jrnUpdatePosting(${i},'amount',this.value)"
          style="background:var(--surface2);border:1px solid var(--border);border-radius:7px;color:var(--text);font-family:var(--mono);font-size:12px;padding:7px 10px;outline:none;text-align:right;">
        <select onchange="jrnUpdatePosting(${i},'direction',this.value)"
          style="background:var(--surface2);border:1px solid var(--border);border-radius:7px;color:var(--text);font-size:12px;padding:7px 10px;outline:none;">
          <option value="debit"  ${p.direction==='debit'  ? 'selected':''}>Debit (+)</option>
          <option value="credit" ${p.direction==='credit' ? 'selected':''}>Credit (−)</option>
        </select>
        <button onclick="jrnRemovePosting(${i})"
          style="background:var(--err-bg);border:1px solid var(--err);color:var(--err);border-radius:6px;padding:6px 8px;cursor:pointer;font-size:13px;line-height:1;${_jrnPostings.length <= 2 ? 'opacity:.3;cursor:not-allowed;' : ''}"
          ${_jrnPostings.length <= 2 ? 'disabled' : ''}>×</button>
      </div>`;
    }).join('');
    jrnCheckBalance();
  }

  function jrnUpdatePosting(i, field, value) {
    _jrnPostings[i][field] = value;
    jrnCheckBalance();
  }

  function jrnAddPosting() {
    _jrnPostings.push({ account_id: '', amount: '', direction: 'credit' });
    jrnRender();
  }

  function jrnRemovePosting(i) {
    if (_jrnPostings.length <= 2) return;
    _jrnPostings.splice(i, 1);
    jrnRender();
  }

  function jrnCheckBalance() {
    let debits = 0, credits = 0;
    _jrnPostings.forEach(p => {
      const amt = parseFloat(p.amount) || 0;
      if (p.direction === 'debit')  debits  += amt;
      if (p.direction === 'credit') credits += amt;
    });
    const note = document.getElementById('jrn-balance-note');
    if (!note) return;
    const diff = Math.abs(debits - credits);
    if (diff < 0.001) {
      note.style.color = 'var(--accent)';
      note.textContent = debits > 0 ? `✓ Balanced — ${dgMoney(debits)}` : '';
    } else {
      note.style.color = 'var(--warn)';
      note.textContent = `Debits ${dgMoney(debits)} · Credits ${dgMoney(credits)} · Difference ${dgMoney(diff)}`;
    }
  }

  async function submitJournalEntry() {
    const date = document.getElementById('jrn-date')?.value.trim() || '';
    const desc = document.getElementById('jrn-desc')?.value.trim() || '';
    const ref  = document.getElementById('jrn-ref')?.value.trim() || '';
    const msg  = document.getElementById('jrn-msg');

    if (!msg) return;
    if (!date || !desc) {
      msg.style.display = ''; msg.style.color = 'var(--err)';
      msg.textContent = 'Date and description are required.'; return;
    }
    const postings = _jrnPostings.map(p => ({
      account_id: parseInt(p.account_id),
      amount_cents: Math.round(parseFloat(p.amount || 0) * 100),
      direction: p.direction,
    }));
    if (postings.some(p => !p.account_id || !p.amount_cents)) {
      msg.style.display = ''; msg.style.color = 'var(--err)';
      msg.textContent = 'All posting lines need an account and amount.'; return;
    }
    const debitTotal  = postings.filter(p=>p.direction==='debit') .reduce((s,p)=>s+p.amount_cents,0);
    const creditTotal = postings.filter(p=>p.direction==='credit').reduce((s,p)=>s+p.amount_cents,0);
    if (debitTotal !== creditTotal) {
      msg.style.display = ''; msg.style.color = 'var(--err)';
      msg.textContent = 'Entry does not balance. Debits must equal credits.'; return;
    }
    msg.style.display = ''; msg.style.color = 'var(--text-soft)';
    msg.textContent = 'Posting…';
    try {
      const res  = await fetch('/api/journal', {
        method: 'POST',
        headers: {'Content-Type':'application/json'},
        body: JSON.stringify({ date, description: desc, reference: ref || null, postings }),
      });
      const data = await res.json();
      if (data.ok || data.id) {
        msg.style.color = 'var(--accent)';
        msg.textContent = '✓ Entry posted.';
        jrnReset();
      } else {
        msg.style.color = 'var(--err)';
        msg.textContent = data.error || 'Error posting entry.';
      }
    } catch(e) {
      msg.style.color = 'var(--err)';
      msg.textContent = 'Network error: ' + e.message;
    }
  }
