// dashboard/js/record_payment.js
// Page: dashboard/record_payment.html
// Opens from clients.html as: record_payment.html?clientId=83
//
// APIs used:
//  - GET  ../api/get_client_details.php?id=CLIENT_ID  (exists; used only for quick header display)
//  - GET  ../api/get_contract_details.php?id=CONTRACT_INTERNAL_ID  (you need this endpoint to load contract+plot+totals)
//  - POST ../api/record_payment.php  (exists; inserts payment + returns invoiceNumber)

(function () {
  const $ = (id) => document.getElementById(id);

  let currentContract = null; // { client, contract, plot, totals }
  let maxPayable = 0;

  // ---------- UI helpers ----------
  function show(el) { if (el) el.classList.remove('hidden'); }
  function hide(el) { if (el) el.classList.add('hidden'); }

  function setText(id, value, fallback = '—') {
    const el = $(id);
    if (!el) return;
    const v = value === null || value === undefined ? '' : String(value);
    el.textContent = v.trim() ? v : fallback;
  }

  function formatMoney(n) {
    const num = Number(n || 0);
    return '₦' + num.toLocaleString(undefined, { minimumFractionDigits: 2, maximumFractionDigits: 2 });
  }

  function toIsoDateInput(d = new Date()) {
    const yyyy = d.getFullYear();
    const mm = String(d.getMonth() + 1).padStart(2, '0');
    const dd = String(d.getDate()).padStart(2, '0');
    return `${yyyy}-${mm}-${dd}`;
  }

  function getQueryParam(name) {
    const url = new URL(window.location.href);
    return url.searchParams.get(name);
  }

  function setLoadError(msg) {
    const el = $('load-error');
    if (!el) return;
    el.textContent = msg;
    show(el);
  }

  function clearLoadError() {
    const el = $('load-error');
    if (!el) return;
    el.textContent = '';
    hide(el);
  }

  function setSubmitError(msg) {
    const el = $('submit-error');
    const ok = $('submit-success');
    if (ok) hide(ok);
    if (!el) return;
    el.textContent = msg;
    show(el);
  }

  function setSubmitSuccess(msg) {
    const el = $('submit-success');
    const err = $('submit-error');
    if (err) hide(err);
    if (!el) return;
    el.textContent = msg;
    show(el);
  }

  function clearSubmitMessages() {
    const err = $('submit-error');
    const ok = $('submit-success');
    if (err) hide(err);
    if (ok) hide(ok);
  }

  // ---------- Amount formatting + words ----------
  function digitsOnly(s) {
    return String(s || '').replace(/[^0-9.]/g, '');
  }

  function addCommasToNumberString(s) {
    // Keep at most 2 decimals if present
    const raw = digitsOnly(s);
    if (!raw) return '';

    const parts = raw.split('.');
    const intPart = parts[0].replace(/^0+(?=\d)/, '');
    const decPart = (parts[1] || '').slice(0, 2);

    const withCommas = intPart.replace(/\B(?=(\d{3})+(?!\d))/g, ',');
    return decPart ? `${withCommas}.${decPart}` : withCommas;
  }

  function parseAmount(s) {
    const raw = digitsOnly(s);
    if (!raw) return 0;
    const num = Number(raw);
    return Number.isFinite(num) ? num : 0;
  }

  function parsePercentage(s) {
    const raw = String(s || '').replace(/[^0-9.]/g, '');
    if (!raw) return 0;
    const parts = raw.split('.');
    const normalized = parts.length > 1 ? `${parts[0]}.${parts.slice(1).join('')}` : raw;
    const num = Number(normalized);
    return Number.isFinite(num) ? num : 0;
  }

  function getFinalPriceBasis() {
    return Number(currentContract?.contract?.FinalPrice || 0);
  }

  function isPercentageMode() {
    return $('payment-entry-mode')?.value === 'PERCENT';
  }

  function percentageAmountMeta() {
    const basis = getFinalPriceBasis();
    const percentage = parsePercentage($('payment-percentage')?.value);
    const amount = basis > 0 && percentage > 0
      ? Math.round((basis * percentage / 100) * 100) / 100
      : 0;

    return { basis, percentage, amount };
  }

  function updatePaymentEntryModeUI() {
    const percentWrap = $('payment-percent-wrap');
    const percentCalc = $('percentage-calculation');
    const amtInput = $('payment-amount');

    if (isPercentageMode()) {
      show(percentWrap);
      if (amtInput) {
        amtInput.readOnly = true;
        amtInput.classList.add('cursor-not-allowed');
      }
    } else {
      hide(percentWrap);
      hide(percentCalc);
      if (amtInput) {
        amtInput.readOnly = false;
        amtInput.classList.remove('cursor-not-allowed');
      }
    }
  }

  function updatePercentageAmount() {
    const hintEl = $('percentage-hint');
    const calcEl = $('percentage-calculation');
    const amtInput = $('payment-amount');

    const meta = percentageAmountMeta();
    if (hintEl) hintEl.textContent = `Calculated from final price: ${formatMoney(meta.basis)}`;

    if (!isPercentageMode()) return meta;

    if (amtInput) {
      amtInput.value = meta.amount ? addCommasToNumberString(meta.amount.toFixed(2)) : '';
    }

    if (calcEl) {
      if (meta.percentage > 0 && meta.amount > 0) {
        calcEl.textContent = `${meta.percentage}% payment = ${formatMoney(meta.amount)}`;
        show(calcEl);
      } else {
        calcEl.textContent = '';
        hide(calcEl);
      }
    }

    return meta;
  }

  function numberToWords(n) {
    // Lightweight English number-to-words (up to trillions) for UI feedback.
    n = Math.floor(Number(n) || 0);
    if (n === 0) return 'zero';

    const a = [
      '', 'one', 'two', 'three', 'four', 'five', 'six', 'seven', 'eight', 'nine',
      'ten', 'eleven', 'twelve', 'thirteen', 'fourteen', 'fifteen', 'sixteen',
      'seventeen', 'eighteen', 'nineteen'
    ];
    const b = ['', '', 'twenty', 'thirty', 'forty', 'fifty', 'sixty', 'seventy', 'eighty', 'ninety'];

    function chunkToWords(num) {
      let str = '';
      if (num >= 100) {
        str += a[Math.floor(num / 100)] + ' hundred';
        num = num % 100;
        if (num) str += ' ';
      }
      if (num >= 20) {
        str += b[Math.floor(num / 10)];
        num = num % 10;
        if (num) str += '-' + a[num];
      } else if (num > 0) {
        str += a[num];
      }
      return str;
    }

    const units = [
      { v: 1_000_000_000_000, w: 'trillion' },
      { v: 1_000_000_000, w: 'billion' },
      { v: 1_000_000, w: 'million' },
      { v: 1_000, w: 'thousand' },
      { v: 1, w: '' },
    ];

    let out = [];
    for (const u of units) {
      if (n >= u.v) {
        const q = Math.floor(n / u.v);
        n = n % u.v;
        const words = chunkToWords(q);
        if (words) out.push(words + (u.w ? ' ' + u.w : ''));
      }
    }
    return out.join(' ').trim();
  }

  function updateAmountUI() {
    const amtInput = $('payment-amount');
    const wordsEl = $('amount-words');
    const maxEl = $('max-payable');
    const submitBtn = $('btn-submit');
    const percentMeta = updatePercentageAmount();

    if (!amtInput) return;

    const formatted = isPercentageMode()
      ? amtInput.value
      : addCommasToNumberString(amtInput.value);
    if (!isPercentageMode()) amtInput.value = formatted;

    const amount = parseAmount(formatted);

    if (maxEl) maxEl.textContent = formatMoney(maxPayable);

    // Words
    if (wordsEl) {
      if (!amount) {
        wordsEl.textContent = 'Amount in words: —';
      } else {
        const naira = Math.floor(amount);
        const kobo = Math.round((amount - naira) * 100);
        let words = numberToWords(naira) + ' naira';
        if (kobo > 0) words += ' and ' + numberToWords(kobo) + ' kobo';
        wordsEl.textContent = 'Amount in words: ' + words;
      }
    }

    // Validation
    let canSubmit = true;
    if (!currentContract) canSubmit = false;
    if (!amount || amount <= 0) canSubmit = false;
    if (amount > maxPayable) canSubmit = false;
    if (maxPayable <= 0) canSubmit = false;
    if (isPercentageMode()) {
      if (!percentMeta.basis || percentMeta.basis <= 0) canSubmit = false;
      if (!percentMeta.percentage || percentMeta.percentage <= 0 || percentMeta.percentage > 100) canSubmit = false;
    }

    if (submitBtn) submitBtn.disabled = !canSubmit;
  }

  // ---------- Boot ----------
  document.addEventListener('DOMContentLoaded', () => {
    // Back
    $('btn-back')?.addEventListener('click', () => (window.location.href = 'clients.html'));

    // Auth (same pattern as your other pages)
    const userJson = localStorage.getItem('user');
    if (!userJson) {
      window.location.href = '../index.html';
      return;
    }

    let user;
    try {
      user = JSON.parse(userJson);
    } catch {
      localStorage.removeItem('user');
      window.location.href = '../index.html';
      return;
    }

    // User info
    if ($('user-fullname')) $('user-fullname').textContent = user.FullName || '';
    if ($('user-role')) $('user-role').textContent = user.Role || '';
    if ($('user-initial')) {
      const initial = (user.FullName || 'U').trim().charAt(0).toUpperCase();
      $('user-initial').textContent = initial || 'U';
    }

    // Default payment date
    if ($('payment-date')) $('payment-date').value = toIsoDateInput(new Date());

    $('payment-entry-mode')?.addEventListener('change', () => {
      clearSubmitMessages();
      updatePaymentEntryModeUI();
      updateAmountUI();
    });

    $('payment-percentage')?.addEventListener('input', () => {
      clearSubmitMessages();
      updateAmountUI();
    });

    // Wire amount input
    $('payment-amount')?.addEventListener('input', () => {
      clearSubmitMessages();
      updateAmountUI();
    });

    // Clear
    $('btn-clear')?.addEventListener('click', () => {
      clearSubmitMessages();
      if ($('payment-date')) $('payment-date').value = toIsoDateInput(new Date());
      if ($('payment-entry-mode')) $('payment-entry-mode').value = 'AMOUNT';
      if ($('payment-percentage')) $('payment-percentage').value = '';
      if ($('payment-amount')) $('payment-amount').value = '';
      if ($('payment-method')) $('payment-method').value = 'Other';
      if ($('payment-reference')) $('payment-reference').value = '';
      if ($('payment-notes')) $('payment-notes').value = '';
      updatePaymentEntryModeUI();
      updateAmountUI();
    });

    // Load contract
    $('btn-load-contract')?.addEventListener('click', () => {
      const id = Number($('contract-id-input')?.value || 0);
      if (!id || id <= 0) {
        setLoadError('Please enter a valid Contract ID (ClientContracts.Id).');
        return;
      }
      loadContractByInternalId(id);
    });

    $('contract-id-input')?.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        e.preventDefault();
        $('btn-load-contract')?.click();
      }
    });

    // If opened with clientId, show quick client info (optional)
    const clientIdFromUrl = Number(getQueryParam('clientId') || 0);
    if (clientIdFromUrl > 0) {
      if ($('hidden-client-id')) $('hidden-client-id').value = String(clientIdFromUrl);
      loadClientQuickInfo(clientIdFromUrl);
    }

    // Submit payment
    $('payment-form')?.addEventListener('submit', async (e) => {
      e.preventDefault();
      clearSubmitMessages();

      if (!currentContract?.contract?.Id) {
        setSubmitError('Load a contract first before recording a payment.');
        return;
      }

      const contractId = Number(currentContract.contract.Id);
      const clientId = Number(
        currentContract.client?.Id ||
        currentContract.contract?.ClientId ||
        $('hidden-client-id')?.value ||
        0
      );

      const paymentDate = $('payment-date')?.value;
      const amount = parseAmount($('payment-amount')?.value);
      const method = $('payment-method')?.value || 'Other';
      const reference = $('payment-reference')?.value || '';
      let notes = $('payment-notes')?.value || '';
      const percentMeta = percentageAmountMeta();

      if (!paymentDate) {
        setSubmitError('Please select a payment date.');
        return;
      }

      if (!amount || amount <= 0) {
        setSubmitError('Please enter a valid payment amount.');
        return;
      }

      if (isPercentageMode()) {
        if (!percentMeta.basis || percentMeta.basis <= 0) {
          setSubmitError('Load a contract with a valid final price before using percentage payment.');
          return;
        }

        if (!percentMeta.percentage || percentMeta.percentage <= 0 || percentMeta.percentage > 100) {
          setSubmitError('Enter a valid payment percentage greater than 0 and not more than 100.');
          return;
        }

        const percentNote = `Payment percentage: ${percentMeta.percentage}% of final price ${formatMoney(percentMeta.basis)} = ${formatMoney(amount)}.`;
        notes = notes.trim() ? `${percentNote}\n${notes.trim()}` : percentNote;
      }

      if (amount > maxPayable) {
        setSubmitError(`Overpayment is not allowed. Maximum payable is ${formatMoney(maxPayable)}.`);
        return;
      }

      const submitBtn = $('btn-submit');
      if (submitBtn) submitBtn.disabled = true;

      try {
        const res = await fetch('../api/record_payment.php', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            contractId,
            clientId,
            amount,
            paymentDate,
            method,
            reference: reference || null,
            notes: notes || null,
          })
        });

        const payload = await res.json().catch(() => null);

        if (!res.ok || !payload || !payload.success) {
          const msg = payload?.message || `Failed to record payment (HTTP ${res.status}).`;
          setSubmitError(msg);
          updateAmountUI();
          return;
        }

        // Redirect immediately to proof upload
        const invoice = payload.invoiceNumber;
        setSubmitSuccess(`Payment recorded. Invoice: ${invoice || '—'}`);

        if (invoice) {
          window.location.href = `upload-proof.php?invoice=${encodeURIComponent(invoice)}`;
          return;
        }

        updateAmountUI();
      } catch (err) {
        console.error(err);
        setSubmitError('Cannot connect to server. Make sure backend is running.');
        updateAmountUI();
      } finally {
        // If redirect happened, irrelevant; otherwise re-validate
        updateAmountUI();
      }
    });

    updatePaymentEntryModeUI();
    updateAmountUI();
  });

  // ---------- Optional: quick client display ----------
  async function loadClientQuickInfo(clientId) {
    try {
      const res = await fetch(`../api/get_client_details.php?id=${encodeURIComponent(clientId)}`);
      if (!res.ok) return;
      const c = await res.json().catch(() => null);
      if (!c?.Id) return;

      setText('client-name', c.FullName);
      setText('client-contact', `${c.Phone || 'No Phone'} | ${c.Email || 'No Email'}`, '—');
      setText('client-clientid', c.ClientId);
    } catch {
      // ignore
    }
  }

  // ---------- Load contract (main) ----------
  async function loadContractByInternalId(contractInternalId) {
    clearLoadError();
    clearSubmitMessages();

    currentContract = null;
    maxPayable = 0;

    if ($('hidden-contract-id')) $('hidden-contract-id').value = '';
    updateAmountUI();

    try {
      const res = await fetch(`../api/get_contract_details.php?id=${encodeURIComponent(contractInternalId)}`);
      const payload = await res.json().catch(() => null);

      if (!res.ok || !payload) {
        setLoadError(`Failed to load contract (HTTP ${res.status}).`);
        return;
      }

      if (payload.success === false) {
        setLoadError(payload.message || 'Failed to load contract.');
        return;
      }

      // Accept either wrapped or semi-wrapped payloads
      const client = payload.client || payload.Client || null;
      const contract = payload.contract || payload.Contract || payload;
      const plot = payload.plot || payload.Plot || null;
      const totals = payload.totals || payload.Totals || null;

      if (!contract?.Id) {
        setLoadError('Contract not found (invalid response).');
        return;
      }

      currentContract = { client, contract, plot, totals };

      // Hidden IDs
      if ($('hidden-contract-id')) $('hidden-contract-id').value = String(contract.Id);
      if (contract.ClientId && $('hidden-client-id')) $('hidden-client-id').value = String(contract.ClientId);

      // Keep input synced
      if ($('contract-id-input')) $('contract-id-input').value = String(contract.Id);

      // Client card
      setText('client-name', client?.FullName || '—');
      setText('client-contact', `${client?.Phone || 'No Phone'} | ${client?.Email || 'No Email'}`);
      setText('client-clientid', client?.ClientId || '—');
      setText('contract-id', contract.Id);
      setText('contract-status', contract.Status || '—');

      // Contract details
      setText('plan-type', contract.PlanType || '—');
      setText('area-name', plot?.AreaName || '—');
      setText('plot-code', plot?.PlotCode || '—');
      setText('original-price', formatMoney(contract.OriginalPrice));
      setText('final-price', formatMoney(contract.FinalPrice));

      // Discount
      const hasDiscount = Number(contract.DiscountAmount || 0) > 0 || !!contract.DiscountCode;
      if (hasDiscount) {
        const code = contract.DiscountCode ? `Code: ${contract.DiscountCode}` : 'Discount applied';
        const type = contract.DiscountType
          ? ` (${contract.DiscountType}${contract.DiscountValue ? `: ${contract.DiscountValue}` : ''})`
          : '';
        setText('discount-summary', code + type, '—');
        setText('discount-amount', `Discount amount: ${formatMoney(contract.DiscountAmount || 0)}`, '—');
      } else {
        setText('discount-summary', 'No discount');
        setText('discount-amount', '—');
      }

      // Payment mode (PlanType)
      const isInstallment = String(contract.PlanType || '').toLowerCase().includes('install');
      if (isInstallment) {
        const months = Number(contract.PlanMonths || 0);
        setText('installment-summary', months ? `${months} months` : 'Installment');
        setText('monthly-amount', `Monthly amount: ${formatMoney(contract.MonthlyAmount || 0)}`);
        setText('payment-mode', 'Installment');
      } else {
        setText('installment-summary', 'Full payment');
        setText('monthly-amount', '—');
        setText('payment-mode', 'Full');
      }

      // Totals
      const totalPaid =
        totals ? Number(totals.totalPaid || 0) :
        payload.totalPaid !== undefined ? Number(payload.totalPaid || 0) :
        0;

      let outstanding =
        totals ? Number(totals.outstanding || 0) :
        payload.outstanding !== undefined ? Number(payload.outstanding || 0) :
        (Number(contract.FinalPrice || 0) - totalPaid);

      if (!Number.isFinite(outstanding)) outstanding = 0;
      if (outstanding < 0) outstanding = 0;

      setText('total-paid', formatMoney(totalPaid), formatMoney(0));
      setText('outstanding', formatMoney(outstanding), formatMoney(0));

      maxPayable = outstanding;

      updateAmountUI();

      if (maxPayable <= 0) {
        setSubmitError('This contract has no outstanding balance.');
      }
    } catch (err) {
      console.error(err);
      setLoadError('Cannot connect to server. Make sure backend is running.');
    }
  }
})();
