/* MPS-21 offer progressive enhancement.
 *
 * Capability-driven presentation: every offer form (the "Make an offer"
 * form on product pages, and the counter / accept / decline / withdraw
 * forms on the offer detail page) works as a plain POST + redirect with
 * no JS. When JS is available, this intercepts the submit, posts via
 * fetch() with X-Requested-With: XMLHttpRequest, and the server returns
 * JSON instead of a redirect. On AJAX success we navigate to the URL
 * the JSON points at (the offer detail page) — same destination the
 * no-JS redirect would reach — but without a full reload of the
 * originating page first. On AJAX error we surface the message inline.
 *
 * Targets any <form> with class "product-offer-form" (the make-offer
 * form) or "offer-action-form" (the offer-detail action forms).
 */
(function () {
  "use strict";

  function flash(form, text, kind) {
    var el = form.querySelector(".offer-js-flash");
    if (!el) {
      el = document.createElement("p");
      el.className = "offer-js-flash";
      form.appendChild(el);
    }
    el.textContent = text;
    el.className = "offer-js-flash offer-js-flash-" + (kind || "info");
  }

  function handleSubmit(e) {
    // An inline onsubmit="return confirm(...)" on terminal-action forms
    // runs before this listener. If the user cancelled, the event is
    // already defaultPrevented — bail so we don't fire the AJAX request.
    if (e.defaultPrevented) return;
    var form = e.currentTarget;
    e.preventDefault();
    var submitBtn = form.querySelector('[type="submit"]');
    if (submitBtn) submitBtn.disabled = true;

    fetch(form.action, {
      method: "POST",
      body: new FormData(form),
      credentials: "same-origin",
      headers: { "X-Requested-With": "XMLHttpRequest" },
    })
      .then(function (r) {
        return r.json().then(function (j) {
          return { status: r.status, body: j };
        });
      })
      .then(function (res) {
        if (res.status >= 200 && res.status < 300 && res.body && res.body.ok) {
          // Navigate to the offer detail page — the canonical place to
          // view/act on the offer next. (offer_open returns offer_id;
          // the action endpoints return the updated offer object.)
          var offerId =
            res.body.offer_id ||
            (res.body.offer && res.body.offer.id);
          if (offerId) {
            window.location.href = "/o/" + offerId;
            return;
          }
          // No id to redirect to — just reload so server-rendered state
          // (flash, updated offer page) shows.
          window.location.reload();
          return;
        }
        var msg = (res.body && res.body.error) || "Something went wrong.";
        flash(form, msg, "error");
        if (submitBtn) submitBtn.disabled = false;
      })
      .catch(function () {
        // Network error — fall back to a normal submit so the user still
        // gets the server's redirect/flash flow.
        if (submitBtn) submitBtn.disabled = false;
        form.submit();
      });
  }

  function wire() {
    var forms = document.querySelectorAll(
      "form.product-offer-form, form.offer-action-form"
    );
    Array.prototype.forEach.call(forms, function (form) {
      form.addEventListener("submit", handleSubmit);
    });
  }

  // Live state on the offer detail page via a bounded SSE feed. When the
  // offer's state changes (counter / accept / decline / expire / pay) the
  // whole page layout changes (which forms show, the notice, can_act), so
  // the correct response is a full reload. EventSource auto-reconnects
  // when the bounded stream closes.
  function watchOfferState() {
    var page = document.querySelector(".offer-page[data-offer-id]");
    if (!page || !window.EventSource) return;
    var offerId = page.getAttribute("data-offer-id");
    var lastState = parseInt(page.getAttribute("data-offer-state"), 10);
    var es = new EventSource("/o/" + offerId + "/events");
    es.onmessage = function (e) {
      var s;
      try {
        s = JSON.parse(e.data);
      } catch (err) {
        return;
      }
      if (typeof s.state !== "number") return;
      if (isNaN(lastState)) {
        lastState = s.state;
        return;
      }
      if (s.state !== lastState) {
        window.location.reload();
      }
    };
    es.addEventListener("gone", function () {
      es.close();
    });
  }

  function init() {
    wire();
    watchOfferState();
  }

  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    init();
  }
})();
