<?= $this->extend('layout/management_layout') ?>
<?= $this->section('content') ?>

<!-- ===== Styled Confirmation Overlay CSS ===== -->
<style>
  #payConfirmOverlay {
    position: fixed;
    inset: 0;
    display: none;
    background: rgba(0, 0, 0, .5);
    z-index: 1085;
  }

  #payConfirmCard {
    width: min(560px, 92vw);
    margin: 6vh auto;
    background: #fff;
    border-radius: 14px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, .25);
    overflow: hidden;
    font-family: system-ui, -apple-system, Segoe UI, Roboto, Arial, sans-serif;
  }

  #payConfirmHeader {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 14px 18px;
    color: #fff;
    background: linear-gradient(135deg, #198754, #20c997);
  }

  #payConfirmHeader .title {
    font-size: 1.05rem;
    font-weight: 700;
    margin: 0;
  }

  #payConfirmBadge {
    margin-left: auto;
    font-size: .8rem;
    font-weight: 600;
    background: rgba(255, 255, 255, .2);
    padding: 3px 10px;
    border-radius: 999px;
    border: 1px solid rgba(255, 255, 255, .4);
  }

  #payConfirmBody {
    padding: 16px 18px;
  }

  #payConfirmList {
    margin: 10px 0 0;
    padding-left: 1.1rem;
  }

  #payConfirmList li {
    margin: 4px 0;
  }

  .amountRow {
    display: flex;
    gap: 10px;
    align-items: baseline;
    flex-wrap: wrap;
  }

  .amountRow .label {
    opacity: .8;
  }

  .amountRow .pill {
    font-weight: 700;
    letter-spacing: .2px;
    background: #f1f3f5;
    border-radius: 8px;
    padding: 4px 10px;
  }

  #pcOverpay {
    display: none;
    margin-top: 12px;
    padding: 10px 12px;
    border-radius: 10px;
    background: #fff3cd;
    border: 1px solid #ffe69c;
    color: #664d03;
  }

  #payConfirmFooter {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    padding: 12px 18px;
    background: #f8f9fa;
    border-top: 1px solid #eee;
  }

  .payBtn {
    border: 0;
    border-radius: 10px;
    padding: 10px 14px;
    font-weight: 700;
    transition: transform .06s ease;
  }

  .payBtn:active {
    transform: translateY(1px);
  }

  .payBtn.cancel {
    background: #6c757d;
    color: #fff;
  }

  .payBtn.confirm {
    background: #198754;
    color: #fff;
  }

  @media (prefers-color-scheme: dark) {
    #payConfirmCard {
      background: #1f2225;
    }

    #payConfirmBody {
      color: #f1f3f5;
    }

    .amountRow .pill {
      background: #2a2e31;
    }

    #payConfirmFooter {
      background: #191c1f;
      border-top-color: #2a2e31;
    }
  }

  .manual-pay-suggest {
    position: static;
    max-height: 320px;
    overflow-y: auto;
    margin-top: 6px;
    background: var(--bs-body-bg, #fff);
    border: 1px solid rgba(0, 0, 0, .12);
    border-radius: 8px;
    box-shadow: 0 10px 24px rgba(0, 0, 0, .12);
  }
</style>

<div class="container mt-4">
  <h2 class="text-center mt-4 mb-3">Manual Payment</h2>

  <?php if (session()->getFlashdata('success')): ?>
    <div class="alert alert-success"><?= session()->getFlashdata('success') ?></div>
  <?php endif; ?>
  <?php if (session()->getFlashdata('error')): ?>
    <div class="alert alert-danger"><?= session()->getFlashdata('error') ?></div>
  <?php endif; ?>

  <!-- Search form -->
  <form method="get" action="<?= base_url('payment/manual_pay') ?>" class="mb-3">
    <div>
      <div class="input-group">
        <input
          type="text"
          id="manualPaySearchInput"
          name="search_term"
          class="form-control"
          placeholder="Enter Parent Email or Phone"
          required
          autocomplete="off"
          aria-autocomplete="list"
          aria-haspopup="listbox"
          value="<?= esc($searchTermUsedInSearch ?? '') ?>">
        <button class="btn btn-primary" type="submit">Search</button>
      </div>
      <div id="manualPaySuggest" class="list-group manual-pay-suggest d-none" role="listbox"></div>
    </div>
  </form>

  <?php if ($parent): ?>
    <!-- Parent + Student info -->
    <div class="row mb-4">
      <div class="col-md-6">
        <div class="card">
          <div class="card-header">Parent Information</div>
          <div class="card-body">
            <p><strong>Name:</strong> <?= esc($parent['firstname']) ?> <?= esc($parent['lastname']) ?></p>
            <p><strong>Phone:</strong> <?= esc($parent['cellphone']) ?></p>
            <p><strong>Email:</strong> <?= esc($parent['email']) ?></p>
          </div>
        </div>
      </div>
      <div class="col-md-6">
        <div class="card">
          <div class="card-header">Students</div>
          <div class="card-body">
            <?php if (!empty($students)): ?>
              <ul class="list-group">
                <?php foreach ($students as $student): ?>
                  <li class="list-group-item"><?= esc($student['firstname']) ?> <?= esc($student['lastname']) ?></li>
                <?php endforeach; ?>
              </ul>
            <?php else: ?>
              <p>No students found.</p>
            <?php endif; ?>
          </div>
        </div>
      </div>
    </div>

    <!-- Payments table -->
    <h5>Payments</h5>
    <table class="table table-bordered no-mgmt-sticky">
      <thead>
        <tr>
          <th>Paid Date</th>
          <th>Paid Amount</th>
          <th>Invoice Balance</th>
          <th>Payment Method</th>
          <th>Check Number</th>
          <th>Installments</th>
          <th>Payment Status</th>
          <th>Invoice Status</th>
          <th>Check/Card File</th>
          <th>Action</th>
        </tr>
      </thead>
      <tbody>
        <?php foreach ($payments as $payment): ?>
          <tr>
            <?php
            // Use updated_at if present; else update_at; else payment_date
            $rawTs = $payment['updated_at'] ?? $payment['update_at'] ?? $payment['payment_date'] ?? null;
            if (!empty($rawTs)) {
              try { $paidAt = local_datetime($rawTs, 'm-d-Y h:i A'); }
              catch (\Throwable $e) { $paidAt = '-'; }
            } else { $paidAt = '-'; }
            $method = strtolower(trim((string)($payment['payment_method'] ?? '')));
            ?>
            <td><?= esc($paidAt) ?></td>
            <td>$<?= number_format((float)($payment['paid_amount'] ?? 0), 2) ?></td>
            <td>$<?= number_format((float)($payment['invoice_current_balance'] ?? 0), 2) ?></td>
            <td>
              <?php if ($method === 'cash'): ?>
                <span class="badge" style="background-color:#28a745;color:#fff;">Cash</span>
              <?php elseif ($method === 'check'): ?>
                <span class="badge" style="background-color:#1ba2b9;color:#fff;">Check</span>
              <?php elseif ($method === 'card' || $method === 'debit/credit card'): ?>
                <span class="badge" style="background-color:#007bff;color:#fff;">Card</span>
              <?php else: ?>
                <span class="badge bg-secondary"><?= esc($payment['payment_method'] ?? '') ?></span>
              <?php endif; ?>
            </td>
            <td><?= !empty($payment['check_number']) ? esc($payment['check_number']) : '-' ?></td>
            <td><?= esc($payment['installment_seq'] ?? $payment['number_of_installments'] ?? '') ?></td>
            <td><?= esc($payment['payment_status'] ?? '') ?></td>
            <td><?= esc($payment['invoice_status'] ?? '') ?></td>
            <td>
              <?php if (!empty($payment['check_file'])): ?>
                <a href="#" data-bs-toggle="modal" data-bs-target="#checkModal<?= (int)$payment['id'] ?>">View</a> /
                <a href="<?= base_url('payment/file/' . (int) $payment['id'] . '/download') ?>">Download</a>

                <!-- File Preview Modal -->
                <div class="modal fade" id="checkModal<?= (int)$payment['id'] ?>" tabindex="-1" aria-hidden="true">
                  <div class="modal-dialog modal-dialog-centered modal-lg">
                    <div class="modal-content">
                      <div class="modal-header">
                        <h5 class="modal-title">Check/Card File</h5>
                        <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                      </div>
                      <div class="modal-body text-center">
                        <iframe src="<?= base_url('payment/file/' . (int) $payment['id'] . '/inline') ?>" width="100%" height="600" style="border:none;"></iframe>
                      </div>
                    </div>
                  </div>
                </div>
              <?php else: ?>
                -
              <?php endif; ?>
            </td>
            <td>
              <button class="btn btn-sm btn-secondary" data-bs-toggle="modal" data-bs-target="#editPaymentModal<?= (int)$payment['id'] ?>">Edit</button>
            </td>
          </tr>

          <!-- Edit Payment Modal -->
          <div class="modal fade" id="editPaymentModal<?= (int)$payment['id'] ?>" tabindex="-1" aria-labelledby="editPaymentModalLabel<?= (int)$payment['id'] ?>" aria-hidden="true">
            <div class="modal-dialog">
              <div class="modal-content">
                <form method="post" action="<?= base_url('payment/manual_pay_edit') ?>" enctype="multipart/form-data">
                  <?= csrf_field() ?>
                  <input type="hidden" name="payment_id" value="<?= (int)$payment['id'] ?>">
                  <input type="hidden" name="search_term" value="<?= esc($searchTermUsedInSearch ?? '') ?>">

                  <div class="modal-header">
                    <h5 class="modal-title" id="editPaymentModalLabel<?= (int)$payment['id'] ?>">Edit Payment ID <?= (int)$payment['id'] ?></h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                  </div>
                  <div class="modal-body">
                    <div class="mb-3">
                      <label>Paid Amount</label>
                      <input type="number" step="0.01" name="paid_amount" class="form-control" value="<?= esc($payment['paid_amount']) ?>" required>
                    </div>
                    <div class="mb-3">
                      <label>Payment Method</label>
                      <select name="payment_method" class="form-select edit-payment-method" data-payment-id="<?= (int)$payment['id'] ?>" onchange="ManualPayUI.toggleEditFields(<?= (int)$payment['id'] ?>)" required>
                        <option value="Cash" <?= strtolower($payment['payment_method']) === 'cash'  ? 'selected' : '' ?>>Cash</option>
                        <option value="Check" <?= strtolower($payment['payment_method']) === 'check' ? 'selected' : '' ?>>Check</option>
                        <option value="Card" <?= (strtolower($payment['payment_method']) === 'card' || strtolower($payment['payment_method']) === 'debit/credit card') ? 'selected' : '' ?>>Debit/Credit Card</option>
                      </select>
                    </div>

                    <div class="mb-3 check-number-edit" id="check-number-edit-<?= (int)$payment['id'] ?>" style="display:none;">
                      <label>Check Number</label>
                      <input type="text" name="check_number" class="form-control" value="<?= !empty($payment['check_number']) ? esc($payment['check_number']) : '' ?>">
                    </div>

                    <div class="mb-3" id="payment-file-edit-<?= (int)$payment['id'] ?>" style="display:none;">
                      <label>Replace Payment File (optional)</label>
                      <input type="file" name="payment_file" class="form-control" accept=".jpg,.jpeg,.png,.pdf">
                    </div>
                  </div>
                  <div class="modal-footer">
                    <button type="submit" class="btn btn-success">Save Changes</button>
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                  </div>
                </form>
              </div>
            </div>
          </div>
        <?php endforeach; ?>
      </tbody>
    </table>


    <?php if (isset($pager)): ?>
      <div class="d-flex justify-content-center"><?= $pager->links() ?></div>
    <?php endif; ?>

    <!-- Invoices -->
    <?php if (!empty($invoices)): ?>
      <h5>Invoices</h5>
      <table class="table table-bordered no-mgmt-sticky">
        <thead>
          <tr>
            <th>Invoice #</th>
            <th>Total</th>
            <th>Paid</th>
            <th>Discount</th>
            <th>Refunds</th>
            <th>Balance</th>
            <th>Status</th>
            <th>Due Date</th>
          </tr>
        </thead>
        <tbody>
          <?php foreach ($invoices as $invoice): ?>
            <tr>
              <td><?= esc($invoice['invoice_number']) ?></td>
              <td>$<?= number_format((float)$invoice['total_amount'], 2) ?></td>
              <td>$<?= number_format((float)$invoice['paid_amount'], 2) ?></td>
              <td>$<?= number_format((float)($invoice['discount'] ?? 0), 2) ?></td>
              <td>$<?= number_format((float)($invoice['refund_paid'] ?? 0), 2) ?></td>
              <?php $tblBal = max(0, (float)($invoice['total_amount'] ?? 0) - (float)($invoice['paid_amount'] ?? 0) - (float)($invoice['discount'] ?? 0) - (float)($invoice['refund_paid'] ?? 0)); ?>
              <td>$<?= number_format($tblBal, 2) ?></td>
              <td><?= esc($invoice['status']) ?></td>
              <td><?= esc(!empty($invoice['due_date']) ? local_date($invoice['due_date'], 'm-d-Y') : '') ?></td>
            </tr>
          <?php endforeach; ?>
        </tbody>
      </table>
    <?php endif; ?>

    <div class="text-end mb-3">
      <button class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#addPaymentModal">Add Payment</button>
    </div>

  <?php elseif (isset($parent)): ?>
    <p class="text-danger">Parent found but no payment records.</p>
  <?php endif; ?>
</div>

<!-- ===== Add Payment Modal (Fixed) ===== -->
<div class="modal fade" id="addPaymentModal" tabindex="-1" aria-labelledby="addPaymentModalLabel" aria-hidden="true">
  <div class="modal-dialog">
    <div class="modal-content">
      <form method="post" action="<?= base_url('payment/manual_pay_update') ?>" id="addPaymentForm" enctype="multipart/form-data">
        <?= csrf_field() ?>
        <input type="hidden" name="search_term" value="<?= esc($searchTermUsedInSearch ?? '') ?>">

        <div class="modal-header">
          <h5 class="modal-title" id="addPaymentModalLabel">Add Manual Payment</h5>
          <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
        </div>

        <div class="modal-body">
          <!-- Invoice select -->
          <div class="mb-3">
            <label for="invoice_id" class="form-label">Select Invoice</label>
            <select
              name="invoice_id"
              id="invoice_id"
              class="form-select"
              required
              data-end-date="<?= esc($installmentEndYmd ?? '') ?>">
              <?php if (!empty($invoices)): ?>
                <?php foreach ($invoices as $invoice): ?>
                  <option
                    value="<?= esc($invoice['id']) ?>"
                    data-balance="<?= esc($invoice['balance']) ?>"
                    data-total="<?= esc($invoice['total_amount'] ?? $invoice['total'] ?? '') ?>"
                    data-paid="<?= esc($invoice['paid_amount'] ?? 0) ?>"
                    data-discount="<?= esc($invoice['discount'] ?? 0) ?>"
                    data-refund="<?= esc($invoice['refund_paid'] ?? 0) ?>"
                    data-next-installment="<?= (int)($invoice['next_installment'] ?? 1) ?>">
                    <?php
                      $uiTotal = (float)($invoice['total_amount'] ?? 0);
                      $uiPaid  = (float)($invoice['paid_amount'] ?? 0);
                      $uiDisc  = (float)($invoice['discount'] ?? 0);
                      $uiRef   = (float)($invoice['refund_paid'] ?? 0);
                      $uiBal   = max(0, $uiTotal - $uiPaid - $uiDisc - $uiRef);
                    ?>
                    Invoice <?= esc($invoice['invoice_number']) ?> |
                    Balance: $<?= number_format($uiBal, 2) ?> |
                    Paid: $<?= number_format($uiPaid, 2) ?>
                  </option>
                <?php endforeach; ?>
              <?php else: ?>
                <option value="">No invoices available</option>
              <?php endif; ?>
            </select>
          </div>

          <!-- Method -->
          <div class="mb-3">
            <label for="payment_method" class="form-label">Payment Method</label>
            <select name="payment_method" id="payment_method" class="form-select" required>
              <option value="">Select Method</option>
              <option value="cash">Cash</option>
              <option value="check">Check</option>
              <option value="card">Debit/Credit Card</option>
            </select>
          </div>

          <!-- Check number (only for checks) -->
          <div class="mb-3" id="check-number-field" style="display:none;">
            <label for="check_number" class="form-label">Check Number</label>
            <input type="text" name="check_number" id="check_number" class="form-control" inputmode="numeric" pattern="[0-9\- ]*">
          </div>

          <!-- Receipt upload (check/card) -->
          <div class="mb-3" id="payment-upload" style="display:none;">
            <label for="payment_file" class="form-label">Upload File (optional)</label>
            <input type="file" name="payment_file" id="payment_file" class="form-control" accept=".jpg,.jpeg,.png,.pdf">
            <div class="form-text">For checks and cards, you can attach a receipt or image.</div>
          </div>

          <!-- Payment type -->
          <div class="mb-3">
            <label for="payment_type" class="form-label">Payment Type</label>
            <select name="payment_type" id="payment_type" class="form-select" required>
              <option value="full">Full Payment</option>
              <option value="installment">Installment Payment</option>
            </select>
          </div>

          <!-- Installment section (non-card only) -->
          <div id="installment-section" style="display:none;">
            <div class="row">
              <div class="col-md-6">
                <div class="mb-3">
                  <label for="installment_count" class="form-label">Number of Installments</label>
                  <select name="installment_count" id="installment_count" class="form-select">
                    <!-- populated by JS -->
                  </select>
                  <div class="form-text">Maximum installments available: <span id="max-installments">0</span></div>
                </div>
              </div>
              <div class="col-md-6">
                <div class="mb-3">
                  <label for="installment_amount" class="form-label">Amount per Installment</label>
                  <input type="number" step="0.01" name="installment_amount" id="installment_amount" class="form-control" readonly>
                </div>
              </div>
            </div>
            <div id="installment-seq-row" class="text-muted small" style="display:none;">
              Next installment sequence: <strong id="installment-seq-label">1</strong>
              <input type="hidden" id="installment_seq" name="installment_seq" value="1">
            </div>
            <div class="text-muted small mt-2">
              Choose the number of installments (up to the maximum available). The first payment is due today.
            </div>
          </div>

          <!-- Amount -->
          <div class="mb-3">
            <label for="amount" class="form-label">Amount</label>
            <input type="number" step="0.01" name="amount" id="amount" class="form-control" required>
            <div id="amount-hint" class="form-text"></div>
          </div>
        </div>

        <div class="modal-footer">
          <button type="submit" class="btn btn-success">Submit Payment</button>
          <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
        </div>
      </form>
    </div>
  </div>
</div>

<!-- ===== Styled Confirmation Overlay (HTML) ===== -->
<div id="payConfirmOverlay" aria-modal="true" role="dialog">
  <div id="payConfirmCard">
    <div id="payConfirmHeader">
      <svg width="18" height="18" viewBox="0 0 24 24" aria-hidden="true" focusable="false">
        <path fill="currentColor" d="M12 2a10 10 0 1 0 10 10A10.011 10.011 0 0 0 12 2m1 15h-2v-2h2zm0-4h-2V7h2z" />
      </svg>
      <h6 class="title">Confirm Payment</h6>
    </div>
    <div id="payConfirmBody">
      <div class="amountRow">
        <div class="label">Amount:</div>
        <div class="pill" id="pcAmount">$0.00</div>
      </div>
      <ul id="payConfirmList">
        <li id="pcInvoice">Invoice —</li>
        <li id="pcMethod">Method —</li>
        <li id="pcType">Type —</li>
        <li id="pcInst" style="display:none;">Installments —</li>
        <li id="pcCheck" style="display:none;">Check # —</li>
        <li id="pcAttach" style="display:none;">Attachment —</li>
        <li id="pcCurrent" style="display:none;">Current Balance —</li>
        <li id="pcAfter" style="display:none;">Balance After —</li>
      </ul>
      <div id="pcOverpay">The amount exceeds the current balance. Please confirm this is intended.</div>
    </div>
    <div id="payConfirmFooter">
      <button type="button" class="payBtn cancel" id="pcBack">Back & Edit</button>
      <button type="button" class="payBtn confirm" id="pcConfirm">Yes, submit</button>
    </div>
  </div>
</div>

<?= $this->endSection() ?>

<?= $this->section('scripts') ?>
<script>
  /* Minimal helper */
  function _el(id) {
    return document.getElementById(id);
  }

  /* Namespaced UI to avoid collisions */
  const ManualPayUI = (() => {
    // Cached elements (Add modal)
    const $invoice = () => _el('invoice_id');
    const $method = () => _el('payment_method');
    const $type = () => _el('payment_type');
    const $amount = () => _el('amount');
    const $amountHint = () => _el('amount-hint');
    const $checkRow = () => _el('check-number-field');
    const $uploadRow = () => _el('payment-upload');
    const $instSec = () => _el('installment-section');
    const $instCount = () => _el('installment_count');
    const $instAmt = () => _el('installment_amount');
    const $instSeqRow = () => _el('installment-seq-row');
    const $instSeqLab = () => _el('installment-seq-label');
    const $instSeq = () => _el('installment_seq');
    const $maxInstLab = () => _el('max-installments');
    const $form = () => _el('addPaymentForm');

    // Confirm overlay elements
    const $overlay = () => _el('payConfirmOverlay');
    const $pcAmount = () => _el('pcAmount');
    const $pcInvoice = () => _el('pcInvoice');
    const $pcMethod = () => _el('pcMethod');
    const $pcType = () => _el('pcType');
    const $pcInst = () => _el('pcInst');
    const $pcCheck = () => _el('pcCheck');
    const $pcAttach = () => _el('pcAttach');
    const $pcCurrent = () => _el('pcCurrent');
    const $pcAfter = () => _el('pcAfter');
    const $pcOverpay = () => _el('pcOverpay');
    const $pcBack = () => _el('pcBack');
    const $pcConfirm = () => _el('pcConfirm');

    let currentInvoiceBalance = 0;
    let confirming = false;

    // Utils
    function currentOpt() {
      const inv = $invoice();
      return inv && inv.options[inv.selectedIndex] ? inv.options[inv.selectedIndex] : null;
    }

    function getBalance() {
      const opt = currentOpt();
      if (!opt) return 0;
      // Compute from total - paid FIRST (more reliable if DB balance is stale)
      const totRaw = opt.getAttribute('data-total');
      const paidRaw = opt.getAttribute('data-paid');
      const discRaw = opt.getAttribute('data-discount');
      const refRaw  = opt.getAttribute('data-refund');
      const tot = (totRaw !== null && totRaw !== '') ? parseFloat(totRaw) : NaN;
      const paid = (paidRaw !== null && paidRaw !== '') ? parseFloat(paidRaw) : NaN;
      const disc = (discRaw !== null && discRaw !== '') ? parseFloat(discRaw) : 0;
      const ref  = (refRaw !== null && refRaw !== '') ? parseFloat(refRaw)  : 0;
      if (isFinite(tot) && isFinite(paid)) {
        const computed = tot - paid - (isFinite(disc) ? disc : 0) - (isFinite(ref) ? ref : 0);
        if (isFinite(computed)) return Math.max(0, computed);
      }
      // Fallback to provided balance
      const raw = opt.getAttribute('data-balance');
      const bal = (raw !== null && raw !== '') ? parseFloat(raw) : NaN;
      return isFinite(bal) ? Math.max(0, bal) : 0;
    }

    function getTotal() {
      const opt = currentOpt();
      const v = opt ? parseFloat(opt.getAttribute('data-total') || '0') : 0;
      return isFinite(v) ? v : 0;
    }

    function getNextInstallmentSeq() {
      const opt = currentOpt();
      const v = opt ? parseInt(opt.getAttribute('data-next-installment') || '1', 10) : 1;
      return isFinite(v) ? v : 1;
    }

    function monthsUntil(endYmd) {
      if (!endYmd) return 0;
      const today = new Date();
      const end = new Date(endYmd + 'T00:00:00');
      if (end <= today) return 0;
      let months = (end.getFullYear() - today.getFullYear()) * 12 + (end.getMonth() - today.getMonth());
      if (end.getDate() > today.getDate()) months += 1;
      return Math.max(0, months);
    }

    function fmtUSD(n) {
      const v = Number(n);
      if (!isFinite(v)) return '—';
      try {
        return new Intl.NumberFormat(undefined, {
          style: 'currency',
          currency: 'USD'
        }).format(v);
      } catch {
        return '$' + v.toFixed(2);
      }
    }

    function esc(s) {
      return String(s).replace(/[&<>"']/g, m => ({
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        '"': '&quot;',
        "'": '&#39;'
      } [m]));
    }

    function debounce(fn, wait = 200) {
      let t;
      return (...args) => {
        clearTimeout(t);
        t = setTimeout(() => fn(...args), wait);
      };
    }

    // Core behaviors
    function updateAmountHint() {
      const bal = getBalance();
      const tot = getTotal();
      if (($method().value || '').toLowerCase() === 'card') {
        $amountHint().textContent = 'Card payments must cover the remaining balance in full.';
      } else {
        $amountHint().textContent = `Remaining balance: ${fmtUSD(bal)} (invoice total: ${fmtUSD(tot)}).`;
      }
    }

    function forceCardRules() {
      // payment type -> full & disabled
      $type().value = 'full';
      $type().setAttribute('disabled', 'disabled');
      // hide installments
      $instSec().style.display = 'none';
      $instSeqRow().style.display = 'none';
      // amount = balance & readonly
      const bal = getBalance();
      $amount().value = bal.toFixed(2);
      $amount().setAttribute('readonly', 'readonly');
      if ($instAmt()) $instAmt().value = '';
      $amountHint().textContent = 'Card payments must cover the remaining balance in full.';
    }

    function setupInstallments() {
      const endDate = $invoice().getAttribute('data-end-date') || '';
      const months = monthsUntil(endDate);
      const bal = getBalance();
      const maxInst = Math.max((months || 0), bal > 0 ? 2 : 0);

      $maxInstLab().textContent = String(maxInst);

      const sel = $instCount();
      sel.innerHTML = '';
      if (maxInst <= 0) {
        const opt = document.createElement('option');
        opt.value = '1';
        opt.textContent = '1';
        sel.appendChild(opt);
      } else {
        for (let i = 2; i <= Math.max(2, maxInst); i++) {
          const opt = document.createElement('option');
          opt.value = String(i);
          opt.textContent = String(i);
          sel.appendChild(opt);
        }
        sel.value = '2';
      }

      // sequence
      const seq = getNextInstallmentSeq();
      $instSeqRow().style.display = '';
      $instSeqLab().textContent = String(seq);
      $instSeq().value = String(seq);
    }

    function recalcInstallments() {
      const bal = getBalance();
      const n = parseInt($instCount().value || '2', 10);
      if (!isFinite(bal) || bal <= 0 || !isFinite(n) || n <= 1) {
        $instAmt().value = '';
        return;
      }
      const per = Math.round((bal / n) * 100) / 100;
      $instAmt().value = per.toFixed(2);
      $amount().removeAttribute('readonly');
      $amount().value = per.toFixed(2);
      $amountHint().textContent = `Paying ${n} installments. First payment is ${fmtUSD(per)} (total balance ${fmtUSD(bal)}).`;
    }

    function applyMethodUI() {
      const m = ($method().value || '').toLowerCase();

      // Toggle check/file rows
      if (m === 'check') {
        $checkRow().style.display = '';
        $uploadRow().style.display = '';
        _el('check_number').required = true;
      } else if (m === 'card') {
        $checkRow().style.display = 'none';
        $uploadRow().style.display = '';
        const chk = _el('check_number');
        if (chk) chk.required = false;
      } else { // cash / empty
        $checkRow().style.display = 'none';
        $uploadRow().style.display = 'none';
        const chk = _el('check_number');
        if (chk) chk.required = false;
      }

      if (m === 'card') {
        forceCardRules();
      } else {
        // enable full/installment select
        $type().removeAttribute('disabled');
        $type().value = 'full';
        $instSec().style.display = 'none';
        $instSeqRow().style.display = 'none';
        $amount().removeAttribute('readonly');
        $amount().value = getBalance().toFixed(2);
        updateAmountHint();
      }
    }

    function applyTypeUI() {
      const m = ($method().value || '').toLowerCase();
      const t = $type().value;

      if (m === 'card') {
        forceCardRules();
        return;
      }
      if (t === 'installment') {
        $instSec().style.display = '';
        setupInstallments();
        recalcInstallments();
      } else {
        $instSec().style.display = 'none';
        $instSeqRow().style.display = 'none';
        $amount().removeAttribute('readonly');
        $amount().value = getBalance().toFixed(2);
        updateAmountHint();
      }
    }

    function onInvoiceChange() {
      const seq = getNextInstallmentSeq();
      $instSeqLab().textContent = String(seq);
      $instSeq().value = String(seq);

      if (($method().value || '').toLowerCase() === 'card') {
        forceCardRules();
      } else {
        updateAmountHint();
        if ($type().value === 'installment') {
          setupInstallments();
          recalcInstallments();
        } else {
          $amount().removeAttribute('readonly');
          $amount().value = getBalance().toFixed(2);
          updateAmountHint();
        }
      }
    }

    // ===== Confirmation overlay =====
    function showOverlay() {
      $overlay().style.display = 'block';
      document.body.style.overflow = 'hidden';
    }

    function hideOverlay() {
      $overlay().style.display = 'none';
      document.body.style.overflow = '';
    }

    function bindConfirmation() {
      const form = $form();
      if (!form) return;

      // click-off and ESC to close
      $overlay().addEventListener('click', (e) => {
        if (e.target === $overlay()) hideOverlay();
      });
      document.addEventListener('keydown', (e) => {
        if ($overlay().style.display === 'block' && e.key === 'Escape') hideOverlay();
      });
      $pcBack().addEventListener('click', hideOverlay);

      $pcConfirm().addEventListener('click', function() {
        confirming = true;
        $pcConfirm().disabled = true;
        hideOverlay();
        // slight delay for UX
        setTimeout(() => form.submit(), 80);
      });

      form.addEventListener('submit', function(e) {
        if (confirming) return; // already confirmed once
        e.preventDefault();
        e.stopImmediatePropagation();

        const invSel = $invoice();
        const invOpt = invSel && invSel.options && invSel.selectedIndex >= 0 ? invSel.options[invSel.selectedIndex] : null;
        const method = ($method().value || '').trim();
        const type = ($type().value || '').trim();
        const amount = parseFloat(($amount().value || '0'));

        if (!invOpt || !invSel.value) {
          alert('Please select an invoice.');
          return;
        }
        if (!method) {
          alert('Please select a payment method.');
          return;
        }
        if (!type) {
          alert('Please select a payment type.');
          return;
        }
        if (!(amount > 0)) {
          alert('Please enter a valid amount > 0.');
          return;
        }

        const invoiceText = invOpt.text || ('Invoice #' + invOpt.value);
        // Derive balance: prefer total - paid - discount - refunds, else fallback to data-balance
        let balance = NaN;
        if (invOpt) {
          const rt = invOpt.getAttribute('data-total');
          const rp = invOpt.getAttribute('data-paid');
          const rd = invOpt.getAttribute('data-discount');
          const rr = invOpt.getAttribute('data-refund');
          const t = (rt !== null && rt !== '') ? parseFloat(rt) : NaN;
          const p = (rp !== null && rp !== '') ? parseFloat(rp) : NaN;
          const d = (rd !== null && rd !== '') ? parseFloat(rd) : 0;
          const r = (rr !== null && rr !== '') ? parseFloat(rr) : 0;
          if (isFinite(t) && isFinite(p)) {
            balance = t - p - (isFinite(d) ? d : 0) - (isFinite(r) ? r : 0);
          }
          if (!isFinite(balance)) {
            const rb = invOpt.getAttribute('data-balance');
            balance = (rb !== null && rb !== '') ? parseFloat(rb) : NaN;
          }
        }
        const nextInst = invOpt.dataset?.nextInstallment || '';
        const instCount = $instCount() ? ($instCount().value || '') : '';
        const instAmt = $instAmt() ? ($instAmt().value || '') : '';
        const checkNo = _el('check_number')?.value?.trim() || '';
        const fileEl = _el('payment_file');
        const file = (fileEl && fileEl.files && fileEl.files[0]) ? fileEl.files[0] : null;

        const newBal = (isFinite(balance) && isFinite(amount)) ? (balance - amount) : NaN;
        const overpay = (isFinite(newBal) && newBal < -0.005);

        $pcAmount().textContent = fmtUSD(amount);
        $pcInvoice().innerHTML = '<strong>Invoice:</strong> ' + esc(invoiceText);
        $pcMethod().innerHTML = '<strong>Payment Method:</strong> ' + esc(method);
        $pcType().innerHTML = '<strong>Payment Type:</strong> ' + (type === 'installment' ? 'Installment' : 'Full');

        if (type === 'installment' && instCount) {
          $pcInst().style.display = '';
          $pcInst().innerHTML = '<strong>Installments:</strong> ' + esc(instCount) + (instAmt ? (' × ' + fmtUSD(instAmt)) : '') + (nextInst ? (' (next #' + esc(nextInst) + ')') : '');
        } else {
          $pcInst().style.display = 'none';
        }

        if (method.toLowerCase() === 'check' && checkNo) {
          $pcCheck().style.display = '';
          $pcCheck().innerHTML = '<strong>Check #:</strong> ' + esc(checkNo);
        } else {
          $pcCheck().style.display = 'none';
        }

        if (file) {
          $pcAttach().style.display = '';
          $pcAttach().innerHTML = '<strong>Attachment:</strong> ' + esc(file.name);
        } else {
          $pcAttach().style.display = 'none';
        }

        if (isFinite(balance)) {
          $pcCurrent().style.display = '';
          $pcCurrent().innerHTML = '<strong>Current Balance:</strong> ' + fmtUSD(balance);
        } else {
          $pcCurrent().style.display = 'none';
        }
        if (isFinite(newBal)) {
          $pcAfter().style.display = '';
          $pcAfter().innerHTML = '<strong>Balance After:</strong> ' + fmtUSD(newBal);
        } else {
          $pcAfter().style.display = 'none';
        }

        $pcOverpay().style.display = overpay ? 'block' : 'none';

        showOverlay();
      });
    }

    // Public: used by edit modals
    function toggleEditFields(paymentId) {
      const select = document.querySelector(`select[data-payment-id='${paymentId}']`);
      const checkField = _el(`check-number-edit-${paymentId}`);
      const fileField = _el(`payment-file-edit-${paymentId}`);
      if (!select || !checkField || !fileField) return;
      const input = checkField.querySelector('input');

      const v = (select.value || '').toLowerCase();
      if (v === 'check') {
        checkField.style.display = 'block';
        fileField.style.display = 'block';
        if (input) input.required = true;
      } else if (v === 'card') {
        checkField.style.display = 'none';
        fileField.style.display = 'block';
        if (input) input.required = false;
      } else {
        checkField.style.display = 'none';
        fileField.style.display = 'none';
        if (input) input.required = false;
      }
    }

    function initSearchSuggest() {
      const input = _el('manualPaySearchInput');
      const suggest = _el('manualPaySuggest');
      if (!input || !suggest) return;

      const suggestUrl = <?= json_encode(site_url('payment/manual_pay_suggest')) ?>;
      let lastRequest = 0;

      function hideSuggest() {
        suggest.classList.add('d-none');
        suggest.innerHTML = '';
      }

      function renderSuggest(items) {
        suggest.innerHTML = '';
        if (!items.length) {
          hideSuggest();
          return;
        }
        items.forEach(item => {
          const btn = document.createElement('button');
          btn.type = 'button';
          btn.className = 'list-group-item list-group-item-action';

          const row = document.createElement('div');
          row.className = 'd-flex justify-content-between gap-2';

          const label = document.createElement('span');
          label.textContent = item.label || '';

          const sub = document.createElement('span');
          sub.className = 'text-muted small';
          sub.textContent = item.sub || '';

          row.appendChild(label);
          row.appendChild(sub);
          btn.appendChild(row);

          btn.addEventListener('click', () => {
            input.value = item.value || item.label || '';
            hideSuggest();
            if (input.form) {
              if (typeof input.form.requestSubmit === 'function') {
                input.form.requestSubmit();
              } else {
                input.form.submit();
              }
            } else {
              input.focus();
            }
          });

          suggest.appendChild(btn);
        });
        suggest.classList.remove('d-none');
      }

      async function loadSuggest(q) {
        const reqId = ++lastRequest;
        try {
          const resp = await fetch(suggestUrl + '?q=' + encodeURIComponent(q), {
            headers: { 'Accept': 'application/json' }
          });
          if (!resp.ok) {
            hideSuggest();
            return;
          }
          const data = await resp.json();
          if (reqId !== lastRequest) return;
          const items = Array.isArray(data.items) ? data.items : [];
          renderSuggest(items);
        } catch (_) {
          hideSuggest();
        }
      }

      const debouncedLoad = debounce(loadSuggest, 200);

      input.addEventListener('input', () => {
        const q = input.value.trim();
        if (q.length < 2) {
          hideSuggest();
          return;
        }
        debouncedLoad(q);
      });

      input.addEventListener('keydown', (e) => {
        if (e.key === 'Escape') hideSuggest();
      });

      document.addEventListener('click', (e) => {
        if (e.target === input || suggest.contains(e.target)) return;
        hideSuggest();
      });
    }

    // Init
    function init() {
      // Normalize initial state
      const inv = $invoice();
      if (inv && inv.options.length > 0) {
        // Prefer the first invoice whose (total - paid) > 0
        let chosen = inv.selectedIndex;
        for (let i = 0; i < inv.options.length; i++) {
          const o = inv.options[i];
          const rt = o.getAttribute('data-total');
          const rp = o.getAttribute('data-paid');
          const rd = o.getAttribute('data-discount');
          const rr = o.getAttribute('data-refund');
          const t = (rt !== null && rt !== '') ? parseFloat(rt) : NaN;
          const p = (rp !== null && rp !== '') ? parseFloat(rp) : NaN;
          const d = (rd !== null && rd !== '') ? parseFloat(rd) : 0;
          const r = (rr !== null && rr !== '') ? parseFloat(rr) : 0;
          let b = (isFinite(t) && isFinite(p)) ? (t - p - (isFinite(d) ? d : 0) - (isFinite(r) ? r : 0)) : NaN;
          if (!isFinite(b)) {
            const rb = o.getAttribute('data-balance');
            b = (rb !== null && rb !== '') ? parseFloat(rb) : NaN;
          }
          if (isFinite(b) && b > 0.005) { chosen = i; break; }
        }
        if (typeof chosen === 'number' && chosen >= 0) inv.selectedIndex = chosen;

        // set balance cache and apply UI
        currentInvoiceBalance = getBalance();
        onInvoiceChange();
      }

      // Listeners (Add modal)
      if (inv) inv.addEventListener('change', onInvoiceChange);
      if ($method()) $method().addEventListener('change', () => {
        applyMethodUI();
      });
      if ($type()) $type().addEventListener('change', () => {
        applyTypeUI();
      });

      const instCountSel = $instCount();
      if (instCountSel) instCountSel.addEventListener('change', recalcInstallments);

      // Setup initial UI per default method/type
      applyMethodUI();
      applyTypeUI();

      // Edit modals
      document.querySelectorAll('.edit-payment-method').forEach(select => {
        const id = select.getAttribute('data-payment-id');
        toggleEditFields(id);
        select.addEventListener('change', () => toggleEditFields(id));
      });

      // Confirm overlay
      bindConfirmation();

      // Search suggestions
      initSearchSuggest();
    }

    return {
      init,
      toggleEditFields
    };
  })();

  // Boot after DOM ready
  document.addEventListener('DOMContentLoaded', ManualPayUI.init);
</script>
<?= $this->endSection() ?>
