"use strict";

import {Controller} from "@hotwired/stimulus";
import "@tailwindplus/elements";

export default class extends Controller {
  connect() {
    this.hide = this.hide.bind(this);
    this.loadDeferredMenu = this.loadDeferredMenu.bind(this);

    // Only close on a true page navigation, NOT on `turbo:before-render`.
    // The render event also fires for in-page Live re-renders (e.g. when a
    // user types into a debounced search input) — using it as a close
    // trigger killed freshly-opened context menus mid-click.
    window.addEventListener("turbo:before-visit", this.hide);

    // A list row ships its actions menu as an unresolved frame (building one
    // walks the workflow and the voters, which is far too much to do for every
    // row up front). Resolve it the moment the menu is asked to open.
    //
    // Deliberately not Turbo's own `loading="lazy"`: that waits for an
    // IntersectionObserver, and an `<el-menu popover>` lives in the top layer,
    // so whether it ever reports as intersecting is not something to bet a
    // blank menu on. `beforetoggle` fires for every way the popover opens —
    // the toggle button and the row's right-click context menu alike.
    this.menu = this.element.querySelector("el-menu");
    if (this.menu) {
      this.menu.addEventListener("beforetoggle", this.loadDeferredMenu);
    }
  }

  disconnect() {
    window.removeEventListener("turbo:before-visit", this.hide);
    if (this.menu) {
      this.menu.removeEventListener("beforetoggle", this.loadDeferredMenu);
    }
    // Intentionally NOT calling hide() here. If morphdom replaces the
    // element, the old popover closes naturally; if the element survives
    // the morph (most common case), forcing a hide would close a popover
    // the user just opened.
  }

  loadDeferredMenu(event) {
    if (event.newState !== "open") {
      return;
    }

    const frame = this.menu.querySelector("turbo-frame[data-src]");
    if (!frame) {
      return;
    }

    // Setting `src` is what makes Turbo fetch. Drop `data-src` first so a
    // second open does not re-request what is already there.
    const src = frame.getAttribute("data-src");
    frame.removeAttribute("data-src");
    frame.setAttribute("src", src);
  }

  hide() {
    if (typeof this.element.hide === "function") {
      this.element.hide();
    }
  }
}
