// Compliance Guard buyer / researcher acknowledgment injector
// (v0.7.253). Runs on the frontend only when the feature is enabled
// in 'custom' or 'both' mode. The merchant supplies a CSS selector
// for either the checkout form OR the submit button. The injector
// inserts a checkbox + label immediately before the submit button,
// then intercepts form submission to block when the checkbox is
// unchecked. Plays well with other validation (capture-phase
// listener, never preventDefault'd unless the box is unchecked).
//
// Designed for the cases the WooCommerce PHP path does not cover:
//   - Custom checkout pages (page builders, fully-custom themes).
//   - Custom-integrated WooCommerce (themes that override the
//     review-order template and skip the standard hook points).
//   - Hybrid setups where the merchant wants the same disclosure on
//     both the Woo checkout AND a secondary upsell flow.
//
// The shortcode `[rpca_buyer_acknowledgment]` is the alternative to
// the auto-injection path - merchants who want manual placement
// drop the shortcode wherever they want and skip the selectors.
(function () {
  "use strict";

  if (typeof window === "undefined" || typeof document === "undefined") {
    return;
  }
  const config = window.RPCABuyerAck;
  if (!config || !config.enabled) {
    return;
  }
  const text = String(config.text || "").trim();
  if (text === "") {
    return;
  }
  const errorMessage = String(config.errorMessage || "Please confirm the research-use acknowledgment before placing your order.");

  // Resolve the form + submit button. Three resolution paths in
  // priority order:
  //   (a) Merchant-supplied form selector. Look for the FIRST submit
  //       button inside the form.
  //   (b) Merchant-supplied submit-button selector. Walk up to the
  //       enclosing form.
  //   (c) Auto-detect: try common WooCommerce / WP form selectors
  //       (form.checkout, form.woocommerce-checkout, .wc-block-
  //       checkout form, form#order_review).
  function resolveTargets() {
    const formSel = String(config.customFormSelector || "").trim();
    const submitSel = String(config.customSubmitSelector || "").trim();
    let form = null;
    let submitButton = null;

    if (formSel) {
      try {
        form = document.querySelector(formSel);
      } catch (_e) {
        form = null;
      }
      if (form) {
        submitButton =
          form.querySelector('button[type="submit"], input[type="submit"], button#place_order, button[name="woocommerce_checkout_place_order"]');
      }
    }
    if (!form && submitSel) {
      try {
        submitButton = document.querySelector(submitSel);
      } catch (_e) {
        submitButton = null;
      }
      if (submitButton) {
        form = submitButton.closest("form");
      }
    }
    if (!form) {
      // Skip forms living inside non-checkout landmarks (theme
      // header / nav / sidebar / footer typically contain a search,
      // newsletter, or login form — never a checkout form). Helper
      // returns true if the candidate is inside any of those zones.
      function isInsideNonCheckoutChrome(el) {
        if (!el || typeof el.closest !== "function") return false;
        return !!el.closest(
          'header, nav, aside, footer, [role="banner"], [role="navigation"], [role="contentinfo"], [role="complementary"], #wpadminbar, .site-header, .site-nav, .site-footer, .widget, .widget-area'
        );
      }
      // A form "looks like a checkout" when it has either (a) several
      // input fields (real checkouts collect name/email/address/etc.)
      // OR (b) an explicit checkout-related submit / payment field /
      // ID / action attribute. The injector prefers forms that score
      // highest on this rubric over the first form on the page.
      function checkoutFormScore(formEl) {
        if (!formEl || isInsideNonCheckoutChrome(formEl)) return -1;
        let score = 0;
        // Many real input fields beats a 1-field search box.
        const inputs = formEl.querySelectorAll(
          'input[type="text"], input[type="email"], input[type="tel"], input[type="number"], input[type="password"], input:not([type]), select, textarea'
        );
        score += Math.min(inputs.length, 20); // capped so a 200-field junk form doesn\'t dominate
        if (inputs.length >= 4) score += 5;   // bonus for a multi-field form (real checkout)
        // Form-level signals.
        const actionAttr = String(formEl.getAttribute("action") || "").toLowerCase();
        const idAttr = String(formEl.getAttribute("id") || "").toLowerCase();
        const classAttr = String(formEl.className || "").toLowerCase();
        const combo = actionAttr + " " + idAttr + " " + classAttr;
        if (/\b(checkout|order|cart|purchase|payment)\b/.test(combo)) score += 10;
        if (/\bsearch\b/.test(combo) || /\bsearchform\b/.test(combo)) score -= 20;
        if (/\b(login|signin|register|signup|newsletter|subscribe|comment|search-form|wp-block-search)\b/.test(combo)) score -= 20;
        // Submit-button signals.
        const submitBtn = formEl.querySelector(
          'button[type="submit"], input[type="submit"], button#place_order, button[name="woocommerce_checkout_place_order"], button.edd-submit, button[id*="place"], button[id*="order"], button[id*="submit"], button[id*="pay"]'
        );
        if (submitBtn) {
          score += 3;
          const btnText = String(submitBtn.textContent || submitBtn.value || "").toLowerCase();
          if (/\b(place\s+order|pay\s+now|complete\s+order|complete\s+purchase|checkout|buy\s+now|review\s+order|submit\s+order|confirm\s+(?:and\s+)?pay)\b/.test(btnText)) {
            score += 10;
          }
          if (/\b(search|subscribe|sign\s*in|log\s*in|register|submit\s+comment)\b/.test(btnText)) {
            score -= 20;
          }
        }
        return score;
      }

      const fallbackSelectors = [
        // WooCommerce
        "form.checkout",
        "form.woocommerce-checkout",
        ".wc-block-checkout form",
        "form#order_review",
        // EDD (Easy Digital Downloads)
        "form#edd_purchase_form",
        "form.edd-cart-checkout-form",
        // Surecart
        "form[data-checkout-form]",
        // Funnelkit / Cartflows
        "form.wcf-checkout-form",
      ];
      // Try the canonical selectors first. They are precise and never
      // match a header/nav form.
      for (let i = 0; i < fallbackSelectors.length; i++) {
        try {
          const candidate = document.querySelector(fallbackSelectors[i]);
          if (candidate && !isInsideNonCheckoutChrome(candidate)) {
            form = candidate;
            break;
          }
        } catch (_e) {
          /* selector not supported in this browser - skip */
        }
      }
      // v0.7.416 (theme-misplacement fix): if no canonical checkout
      // selector matched, score EVERY form on the page and pick the
      // highest-scoring one — but ONLY when the URL looks like a
      // checkout AND the winning form clearly scores like a real
      // checkout (>= 8). Previously the bare "form" fallback picked
      // the FIRST form on the page, which on themes that ship a
      // header search / newsletter / login form ended up injecting
      // the buyer-ack checkbox into the site header. The score
      // floor prevents the same regression — a header search form
      // scores negative so it will never win.
      const path = String(window.location.pathname || "").toLowerCase();
      const looksLikeCheckoutUrl = /\b(checkout|cart|order|payment|buy|purchase)\b/.test(path);
      if (!form && looksLikeCheckoutUrl) {
        let bestForm = null;
        let bestScore = 7; // strict floor: must score > 7 to win
        try {
          const allForms = document.querySelectorAll("form");
          for (let i = 0; i < allForms.length; i++) {
            const candidate = allForms[i];
            const score = checkoutFormScore(candidate);
            if (score > bestScore) {
              bestScore = score;
              bestForm = candidate;
            }
          }
        } catch (_e) {
          bestForm = null;
        }
        if (bestForm) {
          form = bestForm;
        }
      }
      if (form && !submitButton) {
        submitButton =
          form.querySelector('button[type="submit"], input[type="submit"], button#place_order, button[name="woocommerce_checkout_place_order"], button.edd-submit, button[id*="place"], button[id*="order"], button[id*="submit"], button[id*="pay"]');
      }
    }
    return { form, submitButton };
  }

  // Build the checkbox label fragment. The DOM is constructed via
  // createElement / textContent (NOT innerHTML) so a malicious option
  // value cannot inject markup into the page even if PHP sanitization
  // ever regressed.
  function buildCheckboxFragment() {
    const wrapper = document.createElement("label");
    wrapper.className = "rpca-buyer-ack-injected";
    wrapper.setAttribute("data-rpca-buyer-ack", "");
    wrapper.style.display = "flex";
    wrapper.style.alignItems = "flex-start";
    wrapper.style.gap = "8px";
    wrapper.style.margin = "16px 0";
    wrapper.style.fontSize = "14px";
    wrapper.style.lineHeight = "1.4";

    const input = document.createElement("input");
    input.type = "checkbox";
    input.name = "rpca_buyer_ack";
    input.value = "yes";
    input.required = true;
    input.style.marginTop = "3px";
    input.setAttribute("data-rpca-buyer-ack-checkbox", "");

    const span = document.createElement("span");
    span.textContent = text;

    wrapper.appendChild(input);
    wrapper.appendChild(span);

    const errorNote = document.createElement("p");
    errorNote.setAttribute("data-rpca-buyer-ack-error", "");
    errorNote.style.color = "#8B2635";
    errorNote.style.fontSize = "13px";
    errorNote.style.margin = "8px 0 0";
    errorNote.hidden = true;
    errorNote.textContent = errorMessage;

    const container = document.createDocumentFragment();
    container.appendChild(wrapper);
    container.appendChild(errorNote);
    return container;
  }

  // Insert the checkbox once. Idempotent: a re-render of the form
  // (Woo block checkout updates frequently) re-discovers the form
  // and re-inserts only if the marker isn't present.
  function ensureCheckboxInserted() {
    const { form, submitButton } = resolveTargets();
    if (!form) {
      return null;
    }
    if (form.querySelector("[data-rpca-buyer-ack]")) {
      return form;
    }
    const fragment = buildCheckboxFragment();
    if (submitButton && submitButton.parentNode) {
      submitButton.parentNode.insertBefore(fragment, submitButton);
    } else {
      form.appendChild(fragment);
    }
    return form;
  }

  function handleSubmit(event) {
    const form = event.currentTarget;
    if (!form) return;
    const checkbox = form.querySelector("[data-rpca-buyer-ack-checkbox]");
    const errorNote = form.querySelector("[data-rpca-buyer-ack-error]");
    if (!checkbox) {
      return;
    }
    if (checkbox.checked) {
      if (errorNote) errorNote.hidden = true;
      return;
    }
    event.preventDefault();
    event.stopPropagation();
    if (errorNote) {
      errorNote.hidden = false;
      try {
        errorNote.scrollIntoView({ behavior: "smooth", block: "center" });
      } catch (_e) {
        /* older browsers - skip the smooth scroll */
      }
    }
    if (typeof checkbox.focus === "function") {
      checkbox.focus();
    }
  }

  function bind(form) {
    if (!form || form.__rpcaBuyerAckBound) return;
    // capture-phase = true so we run before other submit handlers
    // (Woo's place-order, custom theme handlers) and can cancel them.
    form.addEventListener("submit", handleSubmit, true);
    form.__rpcaBuyerAckBound = true;
  }

  function init() {
    const form = ensureCheckboxInserted();
    if (form) {
      bind(form);
    }
  }

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

  // Observe DOM mutations so block-checkout re-renders are caught.
  // Keep observer cheap: subtree=true but limited to a single form
  // re-discovery per mutation batch via a microtask debounce.
  let pending = false;
  const observer = new MutationObserver(() => {
    if (pending) return;
    pending = true;
    Promise.resolve().then(() => {
      pending = false;
      init();
    });
  });
  if (document.body) {
    observer.observe(document.body, { childList: true, subtree: true });
  } else {
    document.addEventListener("DOMContentLoaded", () => {
      observer.observe(document.body, { childList: true, subtree: true });
    });
  }
})();
