/* Strucon mobile — swipe gestures + animation refinements.
   Uses Pointer Events so it works with touch (phones) AND mouse (desktop
   prototype testing). Non-invasive: attaches listeners at runtime and
   simulates clicks on the existing tabs/close buttons to trigger React. */

(function () {
  const TAB_ORDER = ["dashboard", "diarios", "cameras", "financeiro"];

  let swipeState = null;
  let sheetDragState = null;

  /* ========== Page swipe between tabs ========== */
  function setupPageSwipe() {
    const app = document.querySelector(".mobile-app");
    if (!app || app.__struconSwipe) return;
    app.__struconSwipe = true;

    app.addEventListener("pointerdown", (e) => {
      if (document.querySelector(".m-sheet")) return;
      const t = e.target;
      if (!t.closest) return;
      if (t.closest(".m-tabbar") || t.closest(".m-sheet")) return;
      if (t.closest(".m-hscroll, .m-kpi-scroll, .m-gantt-scroll, input, button, a, video, select, textarea"))
        return;
      if (e.pointerType === "mouse" && e.button !== 0) return;
      const page = app.querySelector(".m-page");
      if (!page) return;
      swipeState = {
        pointerId: e.pointerId,
        x: e.clientX, y: e.clientY,
        dx: 0, dy: 0,
        decided: false, horizontal: false,
        page, startTime: Date.now(),
      };
    });

    app.addEventListener("pointermove", (e) => {
      if (!swipeState || e.pointerId !== swipeState.pointerId) return;
      swipeState.dx = e.clientX - swipeState.x;
      swipeState.dy = e.clientY - swipeState.y;
      if (!swipeState.decided) {
        if (Math.abs(swipeState.dx) > 10 || Math.abs(swipeState.dy) > 10) {
          swipeState.decided = true;
          swipeState.horizontal = Math.abs(swipeState.dx) > Math.abs(swipeState.dy) * 1.3;
        }
      }
      if (swipeState.horizontal && swipeState.page) {
        const active = localStorage.getItem("portal-m-page") || "dashboard";
        const idx = TAB_ORDER.indexOf(active);
        let dx = swipeState.dx;
        if (idx === 0 && dx > 0) dx = dx * 0.35;
        if (idx === TAB_ORDER.length - 1 && dx < 0) dx = dx * 0.35;
        swipeState.page.style.transition = "none";
        swipeState.page.style.transform = `translateX(${dx}px)`;
      }
    });

    const finishSwipe = (e) => {
      if (!swipeState) return;
      if (e && e.pointerId !== swipeState.pointerId) return;
      const { dx, horizontal, page, startTime } = swipeState;
      const dt = Date.now() - startTime;
      const velocity = Math.abs(dx) / Math.max(dt, 1);
      const active = localStorage.getItem("portal-m-page") || "dashboard";
      const idx = TAB_ORDER.indexOf(active);
      let target = null;
      if (horizontal && idx >= 0) {
        const threshold = (page ? page.offsetWidth : window.innerWidth) * 0.25;
        const flick = velocity > 0.5 && Math.abs(dx) > 30;
        if (dx < -threshold || (flick && dx < 0)) {
          if (idx < TAB_ORDER.length - 1) target = TAB_ORDER[idx + 1];
        } else if (dx > threshold || (flick && dx > 0)) {
          if (idx > 0) target = TAB_ORDER[idx - 1];
        }
      }
      if (page) {
        if (target) {
          const dir = target === TAB_ORDER[idx + 1] ? -1 : 1;
          const w = page.offsetWidth || window.innerWidth;
          page.style.transition = "transform 180ms cubic-bezier(0.32,0.72,0,1)";
          page.style.transform = `translateX(${dir * w}px)`;
          setTimeout(() => clickTab(target), 150);
        } else {
          page.style.transition = "transform 220ms cubic-bezier(0.32,0.72,0,1)";
          page.style.transform = "translateX(0)";
          setTimeout(() => { page.style.transition = ""; page.style.transform = ""; }, 230);
        }
      }
      swipeState = null;
    };
    app.addEventListener("pointerup", finishSwipe);
    app.addEventListener("pointercancel", finishSwipe);
  }

  function clickTab(tabId) {
    const buttons = document.querySelectorAll(".m-tabbar .m-tab");
    const order = ["dashboard", "diarios", "cameras", "financeiro", "more"];
    const i = order.indexOf(tabId);
    if (i >= 0 && buttons[i]) buttons[i].click();
  }

  /* ========== Sheet swipe-down-to-close ==========
     Strategy: listen on the sheet; allow drag from ANYWHERE as long as
     (a) the pointer didn't start on an interactive <button>/<a>/<input>,
     or (b) the inner body is scrolled to top.
     If the user starts moving vertically >8px DOWN we "claim" the drag
     and any button clicks are cancelled. */
  function setupSheetSwipe() {
    const sheet = document.querySelector(".m-sheet");
    if (!sheet || sheet.__struconSheet) return;
    sheet.__struconSheet = true;

    sheet.style.touchAction = "pan-y"; // allow vertical gestures
    const handle = sheet.querySelector(".m-sheet-handle");
    const head = sheet.querySelector(".m-sheet-head");
    if (handle) handle.style.touchAction = "none";
    if (head) head.style.touchAction = "none";

    sheet.addEventListener("pointerdown", (e) => {
      if (e.pointerType === "mouse" && e.button !== 0) return;
      const t = e.target;
      if (!t.closest) return;

      // Starting zones
      const onHandle = !!t.closest(".m-sheet-handle");
      const onHead = !!t.closest(".m-sheet-head");
      const onInteractive = !!t.closest("button, a, input, textarea, select");
      const body = sheet.querySelector(".m-sheet-body");
      const bodyAtTop = body ? body.scrollTop <= 0 : true;

      // Eligible to drag if: handle, head, OR body-area (even on buttons)
      //   but if on interactive element we don't preventDefault yet —
      //   only claim the drag once vertical movement exceeds threshold.
      sheetDragState = {
        pointerId: e.pointerId,
        y: e.clientY, x: e.clientX,
        dy: 0, dx: 0,
        startTime: Date.now(),
        onHandle, onHead, onInteractive,
        bodyAtTop,
        claimed: onHandle || onHead,  // claim immediately on handle/head
        originalTarget: t,
      };
    });

    sheet.addEventListener("pointermove", (e) => {
      if (!sheetDragState || e.pointerId !== sheetDragState.pointerId) return;
      const dy = e.clientY - sheetDragState.y;
      const dx = e.clientX - sheetDragState.x;
      sheetDragState.dy = dy;
      sheetDragState.dx = dx;

      // Only downward drag counts
      if (dy <= 0) {
        sheet.style.transform = "";
        const bd = document.querySelector(".m-sheet-backdrop");
        if (bd) bd.style.opacity = "";
        return;
      }

      // If not yet claimed, decide whether to claim based on direction + distance
      if (!sheetDragState.claimed) {
        const movedEnough = Math.abs(dy) > 8;
        const mostlyVertical = Math.abs(dy) > Math.abs(dx) * 1.2;
        if (!movedEnough || !mostlyVertical) return;
        // Can we claim? Only if body at top OR on head/handle
        if (!sheetDragState.bodyAtTop && !sheetDragState.onHandle && !sheetDragState.onHead) {
          return;
        }
        sheetDragState.claimed = true;
        // Kill any would-be click on the originally-clicked element
        try { sheet.setPointerCapture(e.pointerId); } catch (_) {}
      }

      // Drag the sheet with finger
      sheet.style.transition = "none";
      sheet.style.transform = `translateY(${dy}px)`;
      const bd = document.querySelector(".m-sheet-backdrop");
      if (bd) {
        bd.style.transition = "none";
        bd.style.opacity = String(Math.max(0, 1 - dy / 400));
      }
    });

    const finishSheet = (e) => {
      if (!sheetDragState) return;
      if (e && e.pointerId !== sheetDragState.pointerId) return;
      const { dy, startTime, claimed } = sheetDragState;
      const dt = Date.now() - startTime;
      const velocity = dy / Math.max(dt, 1);
      const bd = document.querySelector(".m-sheet-backdrop");

      if (!claimed) {
        // Let the normal click happen (no drag occurred)
        sheetDragState = null;
        return;
      }

      const shouldClose = dy > 100 || velocity > 0.5;
      if (shouldClose) {
        // Smooth exit: slide sheet down, fade backdrop in parallel
        sheet.style.transition = "transform 260ms cubic-bezier(0.32,0.72,0,1)";
        sheet.style.transform = `translateY(100%)`;
        if (bd) {
          bd.style.transition = "opacity 260ms ease-out";
          bd.style.opacity = "0";
        }
        setTimeout(() => {
          // Trigger React close via backdrop click — bypass our own animator
          // since we already animated during the drag.
          const backdrop = document.querySelector(".m-sheet-backdrop");
          if (backdrop) {
            backdrop.__bypass = true;
            backdrop.click();
          }
        }, 240);
      } else {
        // Snap back up
        sheet.style.transition = "transform 320ms cubic-bezier(0.2,0.8,0.2,1)";
        sheet.style.transform = "translateY(0)";
        if (bd) {
          bd.style.transition = "opacity 240ms ease-out";
          bd.style.opacity = "";
        }
        setTimeout(() => {
          sheet.style.transition = "";
          sheet.style.transform = "";
        }, 330);
      }
      sheetDragState = null;
    };

    sheet.addEventListener("pointerup", finishSheet);
    sheet.addEventListener("pointercancel", finishSheet);

    // Intercept click on originally-dragged interactive elements to prevent
    // accidental nav after a drag-close.
    sheet.addEventListener(
      "click",
      (e) => {
        // If we just finished a claimed drag that DIDN'T close, suppress the
        // click on whichever button the pointer ended on.
        if (sheet.__suppressNextClick) {
          sheet.__suppressNextClick = false;
          e.preventDefault();
          e.stopPropagation();
        }
      },
      true
    );
  }

  /* ========== Animate exit on backdrop/row click ==========
     React removes the sheet instantly on close; we intercept the click to
     run a slide-down first, then re-fire the click past our filter. */
  function setupExitAnim() {
    const backdrop = document.querySelector(".m-sheet-backdrop");
    const sheet = document.querySelector(".m-sheet");
    if (!backdrop || !sheet || backdrop.__struconExit) return;
    backdrop.__struconExit = true;

    const animateClose = (afterAnim) => {
      sheet.style.transition = "transform 240ms cubic-bezier(0.32,0.72,0,1)";
      sheet.style.transform = "translateY(100%)";
      backdrop.style.transition = "opacity 240ms ease-out";
      backdrop.style.opacity = "0";
      setTimeout(afterAnim, 230);
    };

    backdrop.addEventListener(
      "click",
      (e) => {
        if (backdrop.__bypass) return;  // re-fired by us below
        e.stopPropagation();
        e.preventDefault();
        animateClose(() => {
          backdrop.__bypass = true;
          backdrop.click();  // React closes now
        });
      },
      true
    );

    // Also animate close when a list row is clicked (navigates away).
    sheet.querySelectorAll(".m-list-row").forEach((row) => {
      if (row.__struconExit) return;
      row.__struconExit = true;
      row.addEventListener(
        "click",
        (e) => {
          if (row.__bypass) return;
          e.stopPropagation();
          e.preventDefault();
          animateClose(() => {
            row.__bypass = true;
            row.click();
          });
        },
        true
      );
    });
  }

  /* ========== Init + observe for dynamic mounts ========== */
  function init() {
    setupPageSwipe();
    setupSheetSwipe();
    setupExitAnim();
  }

  const obs = new MutationObserver(() => init());
  obs.observe(document.body, { childList: true, subtree: true });
  if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", init);
  } else {
    setTimeout(init, 100);
  }
})();
