<script>
// ============================================================
// Shared toast + AJAX form handling.
// Any <form class="ajax-form"> is submitted via fetch() instead of a full
// page POST. The server must respond with JSON: {success, message, redirect?}
// On success: shows a toast, then soft-refreshes #mainContent (or navigates
// to `redirect` first) without a full browser page reload.
// On failure: shows an error toast, re-enables the button, form stays as-is.
//
// This exists instead of disabling buttons on a native form submit because
// disabling the clicked submit button *synchronously* inside its own submit
// handler can cause browsers to drop that button's name/value pair from the
// submitted data entirely (disabled controls are excluded from the form data
// set) - which is what caused the "both buttons spin, nothing happens" bug.
// fetch() captures the form data itself, so this timing problem can't occur.
// ============================================================

function showToast(message, type) {
  type = type || 'success';
  let container = document.getElementById('toastContainer');
  if (!container) {
    container = document.createElement('div');
    container.id = 'toastContainer';
    container.style.cssText = 'position:fixed;top:16px;right:16px;z-index:9999;display:flex;flex-direction:column;gap:8px;max-width:360px;';
    document.body.appendChild(container);
  }
  const colors = { success: '#059669', error: '#dc2626', info: '#1d4ed8' };
  const toast = document.createElement('div');
  toast.style.cssText = `background:${colors[type] || colors.info};color:#fff;font-size:14px;font-weight:500;padding:12px 16px;border-radius:10px;box-shadow:0 4px 12px rgba(0,0,0,.15);opacity:0;transform:translateX(12px);transition:all .25s ease;`;
  toast.textContent = message;
  container.appendChild(toast);
  requestAnimationFrame(() => { toast.style.opacity = '1'; toast.style.transform = 'translateX(0)'; });
  setTimeout(() => {
    toast.style.opacity = '0'; toast.style.transform = 'translateX(12px)';
    setTimeout(() => toast.remove(), 250);
  }, 4200);
}

function setButtonLoading(btn, loading, loadingText) {
  if (!btn) return;
  if (loading) {
    btn.dataset.originalHtml = btn.innerHTML;
    btn.disabled = true;
    btn.style.opacity = '0.7';
    btn.style.cursor = 'not-allowed';
    btn.innerHTML = '<span style="display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.5);border-top-color:#fff;border-radius:50%;vertical-align:-2px;margin-right:6px;animation:ivmspin .6s linear infinite;"></span>' + (loadingText || 'Please wait...');
  } else {
    btn.disabled = false;
    btn.style.opacity = '';
    btn.style.cursor = '';
    if (btn.dataset.originalHtml) btn.innerHTML = btn.dataset.originalHtml;
  }
}

async function refreshMainContent(url) {
  try {
    const res = await fetch(url || window.location.href, { headers: { 'X-Requested-With': 'XMLHttpRequest' } });
    const html = await res.text();
    const doc = new DOMParser().parseFromString(html, 'text/html');
    const newContent = doc.getElementById('mainContent');
    const curContent = document.getElementById('mainContent');
    if (newContent && curContent) {
      curContent.innerHTML = newContent.innerHTML;
      curContent.querySelectorAll('script').forEach(oldScript => {
        const newScript = document.createElement('script');
        if (oldScript.src) newScript.src = oldScript.src; else newScript.textContent = oldScript.textContent;
        oldScript.replaceWith(newScript);
      });
      window.scrollTo({ top: 0, behavior: 'smooth' });
    }
  } catch (e) { console.error('refreshMainContent failed', e); }
}

(function () {
  const styleTag = document.createElement('style');
  styleTag.textContent = '@keyframes ivmspin{to{transform:rotate(360deg)}}';
  document.head.appendChild(styleTag);

  document.addEventListener('submit', async function (e) {
    const form = e.target;
    if (!form.classList || !form.classList.contains('ajax-form')) return;
    e.preventDefault();

    // e.submitter is the button actually clicked - important for forms with
    // more than one named submit button (e.g. Approve vs Reject). Plain
    // FormData(form) does NOT include the clicked button's name/value.
    const btn = e.submitter || form.querySelector('button[type="submit"]') || form.querySelector('button:not([type])');
    if (btn && btn.disabled) return; // already submitting
    setButtonLoading(btn, true, form.dataset.loadingText);

    try {
      const formData = new FormData(form);
      if (btn && btn.name) formData.append(btn.name, btn.value);

      const res = await fetch(form.getAttribute('action') || window.location.href, {
        method: form.getAttribute('method') || 'POST',
        body: formData,
        headers: { 'X-Requested-With': 'XMLHttpRequest' }
      });
      let data;
      try { data = await res.json(); }
      catch (parseErr) { throw new Error('Unexpected response from server.'); }

      showToast(data.message || (data.success ? 'Done.' : 'Something went wrong.'), data.success ? 'success' : 'error');

      if (data.success) {
        if (data.redirect) {
          window.history.pushState({}, '', data.redirect);
          await refreshMainContent(data.redirect);
        } else {
          await refreshMainContent();
        }
      } else {
        setButtonLoading(btn, false);
      }
    } catch (err) {
      showToast('Network error - please try again.', 'error');
      setButtonLoading(btn, false);
    }
  });
})();
</script>
