<!--
  CHANGE DATES WIDGET
  Handles: earlier arrival, later checkout, shift, backward-extend, reduction.

  Paste this block ONCE before </body> (or before the footer include) in
  calendar.php and reservation_form.php.

  Requires: Bootstrap 5 JS. Posts preview to `<page>?date_change_check=1` and
  commit to `move_booking.php`.

  Launch:
    openChangeDates({
      roomingId: 123,
      orderId: 456,               // optional, for context
      guest: 'John Doe',          // optional
      roomNo: '204',              // optional
      checkIn: '2026-08-10',      // current dates (Y-m-d)
      checkOut: '2026-08-14',
      onDone: function(resp){ location.reload(); }   // optional
    });
-->

<div class="modal fade" id="changeDatesModal" tabindex="-1" aria-hidden="true">
  <div class="modal-dialog modal-lg modal-dialog-centered modal-dialog-scrollable">
    <div class="modal-content">
      <div class="modal-header">
        <h5 class="modal-title"><i class="bi bi-calendar-range me-2"></i>Change Dates</h5>
        <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
      </div>
      <div class="modal-body">

        <div id="cdAlert" class="alert d-none" role="alert"></div>

        <div class="row g-2 mb-3">
          <div class="col-md-5">
            <div class="border rounded p-2 h-100">
              <div class="small text-muted text-uppercase fw-semibold mb-1">Booking</div>
              <div class="fw-bold" id="cdGuest">-</div>
              <div class="small text-muted"><span id="cdOrderNo">-</span> · Room <span id="cdRoomNo">-</span></div>
              <div class="small mt-1">Currently <span id="cdOldIn" class="fw-semibold">-</span> → <span id="cdOldOut" class="fw-semibold">-</span></div>
            </div>
          </div>
          <div class="col-md-7">
            <div class="row g-2">
              <div class="col-6">
                <label class="form-label small fw-semibold mb-1">New arrival</label>
                <input type="date" class="form-control" id="cdNewIn">
              </div>
              <div class="col-6">
                <label class="form-label small fw-semibold mb-1">New checkout</label>
                <input type="date" class="form-control" id="cdNewOut">
              </div>
            </div>
            <div class="form-text">Move arrival earlier/later, checkout earlier/later, or both.</div>
          </div>
        </div>

        <div class="mb-3">
          <label class="form-label small fw-semibold d-block mb-1">Pricing for changed nights</label>
          <div class="btn-group" role="group">
            <input type="radio" class="btn-check" name="cdMode" id="cdModeReprice" value="reprice" checked>
            <label class="btn btn-outline-secondary btn-sm" for="cdModeReprice">Reprice from rate plans</label>
            <input type="radio" class="btn-check" name="cdMode" id="cdModePreserve" value="preserve">
            <label class="btn btn-outline-secondary btn-sm" for="cdModePreserve">Keep existing night prices</label>
          </div>
          <div class="form-text">
            <strong>Reprice</strong> re-derives every night from the rate plan.
            <strong>Keep</strong> preserves current nights and only prices the new ones.
          </div>
        </div>

        <div id="cdVerdict" class="d-none"></div>

        <div id="cdPreview" class="d-none mt-2">
          <div class="small text-uppercase fw-semibold text-muted mb-1">Nightly breakdown</div>
          <div class="table-responsive" style="max-height:220px;overflow:auto;">
            <table class="table table-sm align-middle mb-2">
              <thead class="table-light"><tr><th>Night</th><th>Plan</th><th></th><th class="text-end">Amount</th></tr></thead>
              <tbody id="cdNightlyBody"></tbody>
              <tfoot><tr class="table-light fw-bold">
                <td colspan="3" class="text-end">New stay total</td>
                <td class="text-end" id="cdNewTotal">0.00</td>
              </tr></tfoot>
            </table>
          </div>

          <div class="card border-0 bg-light">
            <div class="card-body py-2">
              <h6 class="fw-semibold mb-2"><i class="bi bi-journal-check me-1"></i>Folio impact</h6>
              <table class="table table-sm mb-0">
                <tbody>
                  <tr><td>Projected charges</td><td class="text-end" id="cdCharges">0.00</td></tr>
                  <tr><td>Payments received</td><td class="text-end" id="cdPayments">0.00</td></tr>
                  <tr class="fw-semibold border-top"><td>New balance due</td><td class="text-end" id="cdBalance">0.00</td></tr>
                </tbody>
              </table>
              <div id="cdOverpaid" class="alert alert-warning py-1 px-2 small mb-0 mt-2 d-none">
                <i class="bi bi-exclamation-triangle me-1"></i>
                <span id="cdOverpaidMsg"></span>
              </div>
            </div>
          </div>
        </div>

      </div>
      <div class="modal-footer">
        <button type="button" class="btn btn-outline-secondary" data-bs-dismiss="modal">Cancel</button>
        <button type="button" class="btn btn-outline-primary" id="cdPreviewBtn"><i class="bi bi-eye me-1"></i>Preview</button>
        <button type="button" class="btn btn-primary" id="cdApplyBtn" disabled><i class="bi bi-check2-circle me-1"></i>Apply Change</button>
      </div>
    </div>
  </div>
</div>

<script>
(function () {
  // move_booking.php and the date_change_check endpoint (in calendar.php) both
  // live in rooms/modules/calendar/. This widget is included from pages in
  // different folders (calendar/ and reservations/), so use absolute web-root
  // paths rather than relative ones.
  const MOVE_URL  = '/rooms/modules/calendar/move_booking.php';
  const CHECK_URL = '/rooms/modules/calendar/calendar.php';
  let cd = { roomingId: 0, orderId: 0, oldIn: '', oldOut: '', onDone: null };

  function el(id) { return document.getElementById(id); }
  function money(n) { return Number(n || 0).toFixed(2); }

  function cdAlert(msg, kind) {
    const b = el('cdAlert');
    b.className = 'alert alert-' + (kind || 'info');
    b.textContent = msg;
    b.classList.remove('d-none');
  }
  function cdClear() { el('cdAlert').classList.add('d-none'); }

  function cdMode() {
    const s = document.querySelector('input[name="cdMode"]:checked');
    return s ? s.value : 'reprice';
  }

  function cdResetPreview() {
    el('cdPreview').classList.add('d-none');
    el('cdVerdict').classList.add('d-none');
    el('cdApplyBtn').disabled = true;
    el('cdNightlyBody').innerHTML = '';
  }

  async function cdRunPreview() {
    cdClear();
    const newIn = el('cdNewIn').value;
    const newOut = el('cdNewOut').value;
    if (!newIn || !newOut) { cdAlert('Pick both new dates.', 'warning'); return; }
    if (newOut <= newIn) { cdAlert('Checkout must be after arrival.', 'warning'); return; }
    if (newIn === cd.oldIn && newOut === cd.oldOut) { cdAlert('Dates are unchanged.', 'info'); return; }

    el('cdPreviewBtn').disabled = true;
    const url = CHECK_URL + '?date_change_check=1'
      + '&rooming_id=' + encodeURIComponent(cd.roomingId)
      + '&new_check_in=' + encodeURIComponent(newIn)
      + '&new_check_out=' + encodeURIComponent(newOut)
      + '&mode=' + encodeURIComponent(cdMode());

    let data;
    try {
      const res = await fetch(url, { credentials: 'same-origin' });
      data = await res.json();
    } catch (e) {
      el('cdPreviewBtn').disabled = false;
      cdAlert('Preview failed (bad response).', 'danger');
      return;
    }
    el('cdPreviewBtn').disabled = false;

    if (!data.ok) { cdAlert(data.message || 'Preview failed.', 'danger'); cdResetPreview(); return; }

    if (data.available === false) {
      let msg = data.message || 'Not available.';
      if (data.blockers && data.blockers.length) {
        msg += ' Conflicts: ' + data.blockers.map(function (b) {
          return b.order_no + ' (' + b.guest + ' ' + b.check_in + '→' + b.check_out + ')';
        }).join(', ');
      }
      el('cdVerdict').className = 'alert alert-danger';
      el('cdVerdict').textContent = msg;
      el('cdVerdict').classList.remove('d-none');
      cdResetPreview();
      el('cdVerdict').classList.remove('d-none');
      return;
    }

    // Verdict summary
    const addN = (data.added || []).length, remN = (data.removed || []).length;
    let verdict = 'Room ' + data.room_no + ' is free. ' + data.nights + ' night(s)';
    if (addN) verdict += ', +' + addN + ' new';
    if (remN) verdict += ', −' + remN + ' removed';
    verdict += '.';
    el('cdVerdict').className = 'alert alert-success py-1 px-2 small';
    el('cdVerdict').textContent = verdict;
    el('cdVerdict').classList.remove('d-none');

    // Nightly table
    const body = el('cdNightlyBody');
    body.innerHTML = '';
    (data.nightly || []).forEach(function (n) {
      const badge = n.source === 'new' ? '<span class="badge bg-primary">new</span>'
        : (n.source === 'existing' ? '<span class="badge bg-secondary">kept</span>'
        : (n.source === 'repriced' ? '<span class="badge bg-info text-dark">repriced</span>'
        : (n.source === 'no_rate' ? '<span class="badge bg-danger">no rate</span>' : '')));
      const amt = (n.total === null || n.total === undefined) ? '—' : money(n.total);
      const tr = document.createElement('tr');
      tr.innerHTML = '<td>' + n.date + '</td><td>' + (n.plan || '') + '</td><td>' + badge + '</td>'
        + '<td class="text-end">' + amt + '</td>';
      body.appendChild(tr);
    });
    el('cdNewTotal').textContent = money(data.new_total);

    el('cdCharges').textContent = money(data.projected_charges);
    el('cdPayments').textContent = money(data.payments);
    el('cdBalance').textContent = money(data.projected_balance);

    if (data.is_overpaid) {
      el('cdOverpaidMsg').textContent = 'Payments exceed the new total by ' + money(data.overpaid)
        + '. A refund may be due. You can still apply the change.';
      el('cdOverpaid').classList.remove('d-none');
    } else {
      el('cdOverpaid').classList.add('d-none');
    }

    if (!data.rates_known) {
      cdAlert('Some nights have no rate for the chosen plan/date. Applying will fail for those — switch mode or add a rate.', 'warning');
    }

    el('cdPreview').classList.remove('d-none');
    el('cdApplyBtn').disabled = false;
  }

  async function cdApply() {
    cdClear();
    const newIn = el('cdNewIn').value, newOut = el('cdNewOut').value;
    if (!newIn || !newOut) { cdAlert('Pick both dates.', 'warning'); return; }
    if (el('cdPreview').classList.contains('d-none')) { cdAlert('Preview first.', 'info'); return; }

    const bal = el('cdBalance').textContent;
    let confirmMsg = 'Apply new dates ' + newIn + ' → ' + newOut + '?\n\nNew balance due: ' + bal + '.';
    if (!el('cdOverpaid').classList.contains('d-none')) {
      confirmMsg += '\n\n' + el('cdOverpaidMsg').textContent;
    }
    if (!confirm(confirmMsg)) return;

    const body = new FormData();
    body.append('order_id', cd.orderId);
    body.append('rooming_id', cd.roomingId);
    body.append('check_in', newIn);
    body.append('check_out', newOut);
    body.append('reprice_mode', cdMode());
    // move_booking treats room_id=0 as "move to Holding Area", so we MUST send
    // the booking's current room to keep it in place on a pure date change.
    if (!cd.roomId) {
      el('cdApplyBtn').disabled = false;
      cdAlert('Cannot change dates: this booking has no allocated room (it is in Holding). Allocate a room first.', 'danger');
      return;
    }
    body.append('room_id', cd.roomId);

    el('cdApplyBtn').disabled = true;
    let data;
    try {
      const res = await fetch(MOVE_URL, { method: 'POST', body: body, credentials: 'same-origin' });
      data = await res.json();
    } catch (e) {
      el('cdApplyBtn').disabled = false;
      cdAlert('Apply failed (bad response).', 'danger');
      return;
    }

    if (!data.ok) { cdAlert(data.message || 'Apply failed.', 'danger'); el('cdApplyBtn').disabled = false; return; }

    cdAlert(data.message || 'Dates updated.', 'success');
    if (typeof cd.onDone === 'function') setTimeout(function () { cd.onDone(data); }, 900);
  }

  window.openChangeDates = function (opts) {
    opts = opts || {};
    cd.roomingId = parseInt(opts.roomingId, 10) || 0;
    cd.orderId = parseInt(opts.orderId, 10) || 0;
    cd.roomId = parseInt(opts.roomId, 10) || 0;
    cd.oldIn = opts.checkIn || '';
    cd.oldOut = opts.checkOut || '';
    cd.onDone = opts.onDone || null;
    if (!cd.roomingId) { alert('No rooming id.'); return; }

    el('cdGuest').textContent = opts.guest || 'Guest';
    el('cdOrderNo').textContent = opts.orderNo || ('#' + (cd.orderId || ''));
    el('cdRoomNo').textContent = opts.roomNo || '-';
    el('cdOldIn').textContent = cd.oldIn || '-';
    el('cdOldOut').textContent = cd.oldOut || '-';
    el('cdNewIn').value = cd.oldIn || '';
    el('cdNewOut').value = cd.oldOut || '';
    el('cdModeReprice').checked = true;
    cdClear();
    cdResetPreview();
    el('cdOverpaid').classList.add('d-none');

    bootstrap.Modal.getOrCreateInstance(el('changeDatesModal')).show();
  };

  document.addEventListener('DOMContentLoaded', function () {
    const pv = el('cdPreviewBtn'), ap = el('cdApplyBtn');
    if (pv) pv.addEventListener('click', cdRunPreview);
    if (ap) ap.addEventListener('click', cdApply);
    ['cdNewIn', 'cdNewOut'].forEach(function (id) {
      const f = el(id); if (f) f.addEventListener('change', cdResetPreview);
    });
    document.querySelectorAll('input[name="cdMode"]').forEach(function (r) {
      r.addEventListener('change', cdResetPreview);
    });
  });
})();
</script>
