/**
 * improvement-modal — Shift+click any dashboard widget to suggest an improvement.
 *
 * Usage (once per page, usually via _footer.md):
 *   import {initImprovementModal} from "./components/improvement-modal.js";
 *   initImprovementModal({apiBase: "http://127.0.0.1:8000"});
 *
 * Widget names can be declared explicitly via data attribute:
 *   <div data-widget-name="Workstreams by Domain">…</div>
 *
 * Otherwise the component walks the DOM to infer the nearest section heading.
 * Submissions are stored as technical-debt items with debt_type="dashboard-improvement".
 *
 * Interaction:
 *   - Hold Shift → cursor changes to crosshair across the entire page
 *   - Shift+click any element (except form controls) → opens suggestion modal
 */

const _STYLE_ID = "improvement-modal-styles";

function _ensureStyles() {
  if (typeof document === "undefined" || document.getElementById(_STYLE_ID)) return;
  const s = document.createElement("style");
  s.id = _STYLE_ID;
  s.textContent = `
/* ── Backdrop ──────────────────────────────────────────────────────────── */
.impr-modal {
  position: fixed; inset: 0; background: rgba(0,0,0,0.42);
  z-index: 9200; display: flex; align-items: center; justify-content: center;
  animation: _im-fade 0.15s ease;
}
@keyframes _im-fade { from { opacity:0 } to { opacity:1 } }

/* ── Box ────────────────────────────────────────────────────────────────── */
.impr-modal-box {
  width: min(480px, 92vw); max-height: 90vh;
  background: var(--theme-background, #fff); border-radius: 12px;
  box-shadow: 0 20px 60px rgba(0,0,0,0.30);
  display: flex; flex-direction: column;
  animation: _im-rise 0.15s ease; overflow: hidden;
}
@keyframes _im-rise {
  from { transform: translateY(12px); opacity: 0 }
  to   { transform: translateY(0);    opacity: 1 }
}

/* ── Header ─────────────────────────────────────────────────────────────── */
.impr-header {
  display: flex; align-items: center; gap: 0.55rem;
  padding: 0.8rem 1rem 0.75rem;
  border-bottom: 1px solid var(--theme-foreground-faint, #e4e4e4);
  background: var(--theme-background-alt, #f7f7f7); flex-shrink: 0;
}
.impr-header-icon { font-size: 1.1rem; flex-shrink: 0; line-height: 1; }
.impr-header-title {
  flex: 1; font-size: 0.95rem; font-weight: 700;
  color: var(--theme-foreground, #111); margin: 0;
}
.impr-header-close {
  background: none; border: 1px solid transparent; cursor: pointer;
  font-size: 0.82rem; color: var(--theme-foreground-muted, #999);
  padding: 0.15rem 0.42rem; border-radius: 6px; flex-shrink: 0;
  font-family: inherit; line-height: 1.3;
  transition: background 0.1s, border-color 0.1s;
}
.impr-header-close:hover {
  border-color: var(--theme-foreground-faint, #ccc);
  background: var(--theme-background, #fff);
  color: var(--theme-foreground, #111);
}

/* ── Body ───────────────────────────────────────────────────────────────── */
.impr-body {
  padding: 0.85rem 1rem 0.25rem; overflow-y: auto;
  display: flex; flex-direction: column; gap: 0.6rem; flex: 1;
}
.impr-field-label {
  font-size: 0.7rem; font-weight: 700; text-transform: uppercase;
  letter-spacing: 0.06em; color: var(--theme-foreground-faint, #aaa);
  margin-bottom: 0.18rem;
}
.impr-context-chip {
  font-size: 0.82rem; color: var(--theme-foreground-muted, #555);
  background: var(--theme-background-alt, #f4f4f4);
  border: 1px solid var(--theme-foreground-faint, #e0e0e0);
  border-radius: 6px; padding: 0.32rem 0.65rem;
  word-break: break-word; line-height: 1.45;
}
.impr-textarea {
  width: 100%; box-sizing: border-box;
  min-height: 106px; resize: vertical;
  font-size: 0.87rem; font-family: inherit; line-height: 1.55;
  color: var(--theme-foreground, #111);
  background: var(--theme-background, #fff);
  border: 1px solid var(--theme-foreground-faint, #ccc);
  border-radius: 7px; padding: 0.5rem 0.7rem; outline: none;
  transition: border-color 0.12s, box-shadow 0.12s;
}
.impr-textarea:focus {
  border-color: #6366f1;
  box-shadow: 0 0 0 2px rgba(99,102,241,0.18);
}
.impr-textarea.impr-error { border-color: #e53e3e; }
.impr-hint {
  font-size: 0.71rem; color: var(--theme-foreground-faint, #bbb);
  margin-top: 0.15rem;
}

/* ── Footer ─────────────────────────────────────────────────────────────── */
.impr-footer {
  display: flex; justify-content: flex-end; gap: 0.45rem;
  padding: 0.7rem 1rem 0.8rem; flex-shrink: 0;
  border-top: 1px solid var(--theme-foreground-faint, #e4e4e4);
}
.impr-btn {
  padding: 0.38rem 1rem; border-radius: 7px;
  font-size: 0.83rem; cursor: pointer; font-family: inherit;
  font-weight: 600; border: 1px solid transparent;
  transition: background 0.12s, opacity 0.12s;
}
.impr-btn-cancel {
  background: var(--theme-background-alt, #f1f1f1);
  border-color: var(--theme-foreground-faint, #ddd);
  color: var(--theme-foreground-muted, #666);
}
.impr-btn-cancel:hover { background: var(--theme-foreground-faint, #e6e6e6); }
.impr-btn-submit { background: #6366f1; color: #fff; }
.impr-btn-submit:hover:not(:disabled) { background: #4f46e5; }
.impr-btn-submit:disabled { opacity: 0.5; cursor: not-allowed; }

/* ── Toast ──────────────────────────────────────────────────────────────── */
.impr-toast {
  position: fixed; bottom: 1.4rem; left: 50%; transform: translateX(-50%);
  background: #1e1b4b; color: #e0e7ff; border-radius: 8px;
  padding: 0.5rem 1.15rem; font-size: 0.82rem; font-weight: 500;
  z-index: 9300; box-shadow: 0 4px 24px rgba(0,0,0,0.28);
  white-space: nowrap; pointer-events: none;
  animation: _im-tin 0.18s ease, _im-tout 0.28s ease 1.7s forwards;
}
@keyframes _im-tin  { from { opacity:0; transform:translateX(-50%) translateY(6px) } to { opacity:1; transform:translateX(-50%) translateY(0) } }
@keyframes _im-tout { from { opacity:1 } to { opacity:0 } }

/* ── Shift-held mode: cursor + element highlighting ─────────────────────── */
.impr-mode-shift,
.impr-mode-shift * { cursor: copy !important; }

/* Highlight annotatable elements in main content, left nav, and right TOC */
.impr-mode-shift #observablehq-main figure,
.impr-mode-shift #observablehq-main h2,
.impr-mode-shift #observablehq-main h3,
.impr-mode-shift #observablehq-main h4,
.impr-mode-shift #observablehq-main [data-widget-name],
.impr-mode-shift #observablehq-sidebar a,
.impr-mode-shift #observablehq-sidebar summary,
.impr-mode-shift #observablehq-toc a,
.impr-mode-shift #observablehq-toc .kpi-infobox,
.impr-mode-shift #observablehq-toc [id] {
  outline: 1px dashed rgba(99, 102, 241, 0.45);
  background: rgba(99, 102, 241, 0.055) !important;
  border-radius: 4px;
  transition: background 0.1s, outline 0.1s;
}
`;
  document.head.append(s);
}

/* ── Widget name inference ─────────────────────────────────────────────── */
function _inferWidgetName(target) {
  // 0a. Right-margin TOC: link text, KPI box title, or nearest labelled container
  if (target.closest("#observablehq-toc")) {
    const link = target.closest("a");
    if (link) return (link.textContent.trim() || "TOC link") + " (TOC)";
    const kpiTitle = target.closest(".kpi-infobox")
      ?.querySelector(".kpi-infobox-title");
    if (kpiTitle) return kpiTitle.textContent.trim() + " (sidebar widget)";
    const labelled = target.closest("[id]");
    if (labelled) return labelled.id.replace(/-/g, " ") + " (TOC)";
    return "Right margin";
  }

  // 0b. Left sidebar navigation: nav link text or section heading
  if (target.closest("#observablehq-sidebar")) {
    const link    = target.closest("a");
    if (link)    return link.textContent.trim() || "Nav link";
    const summary = target.closest("summary");
    if (summary) return summary.textContent.trim() || "Nav section";
    return target.textContent.trim() || "Navigation";
  }

  // 1. Explicit data-widget-name on self or ancestor
  let el = target;
  while (el && el !== document.body) {
    if (el.dataset?.widgetName) return el.dataset.widgetName;
    el = el.parentElement;
  }

  // 2. Direct child heading inside a container (chart cards etc.)
  el = target;
  const main = document.querySelector("#observablehq-main") ?? document.body;
  while (el && el !== main) {
    const h = el.querySelector(":scope > h2, :scope > h3, :scope > h4");
    if (h) return h.textContent.trim();
    el = el.parentElement;
  }

  // 3. Nearest preceding sibling or ancestor heading in the main flow
  el = target;
  while (el && el !== main) {
    let sib = el.previousElementSibling;
    while (sib) {
      if (sib.matches("h2, h3, h4")) return sib.textContent.trim();
      const inner = sib.querySelector("h2, h3, h4");
      if (inner) return inner.textContent.trim();
      sib = sib.previousElementSibling;
    }
    el = el.parentElement;
  }

  // 4. Page h1 as final fallback
  return document.querySelector("#observablehq-main h1, h1")?.textContent?.trim()
    ?? "Dashboard page";
}

/* ── Toast helper ──────────────────────────────────────────────────────── */
function _toast(msg) {
  document.querySelector(".impr-toast")?.remove();
  const t = document.createElement("div");
  t.className = "impr-toast";
  t.textContent = msg;
  document.body.append(t);
  setTimeout(() => t.remove(), 2100);
}

/* ── Module-level guard — one listener per page load ──────────────────── */
let _initialized = false;

/**
 * Wire Shift+click → improvement modal on the current page.
 * Safe to call multiple times — only the first call takes effect.
 *
 * @param {object} opts
 * @param {string} opts.apiBase  State Hub API base URL (default: "http://127.0.0.1:8000")
 * @param {string} opts.domain   Domain slug for the TD record  (default: "custodian")
 */
export function initImprovementModal({ apiBase = "http://127.0.0.1:8000", domain = "custodian" } = {}) {
  if (_initialized) return;
  _initialized = true;
  _ensureStyles();

  // Track modifier state. Highlighting is delayed 1 s so normal Shift+typing
  // doesn't trigger the visual mode change; releasing Shift cancels immediately.
  let _shiftTimer = null;
  function _updateMode(e) {
    if (e.shiftKey) {
      if (!_shiftTimer && !document.body.classList.contains("impr-mode-shift")) {
        _shiftTimer = setTimeout(() => {
          document.body.classList.add("impr-mode-shift");
          _shiftTimer = null;
        }, 1000);
      }
    } else {
      clearTimeout(_shiftTimer);
      _shiftTimer = null;
      document.body.classList.remove("impr-mode-shift");
    }
  }
  window.addEventListener("keydown",   _updateMode);
  window.addEventListener("keyup",     _updateMode);
  window.addEventListener("mousemove", _updateMode);
  // Clear on blur in case Shift is held when the window loses focus
  window.addEventListener("blur", () => {
    clearTimeout(_shiftTimer);
    _shiftTimer = null;
    document.body.classList.remove("impr-mode-shift");
  });

  document.addEventListener("click", (e) => {
    if (!e.shiftKey) return;
    const inSidebar = !!e.target.closest("#observablehq-sidebar");
    const inToc     = !!e.target.closest("#observablehq-toc");
    // Block shift-clicks on form controls; allow nav/toc links (preventDefault stops navigation)
    if (!inSidebar && !inToc && e.target.matches("input, textarea, select, a, button")) return;
    if ((inSidebar || inToc) && e.target.matches("input, textarea, select")) return;

    e.preventDefault();

    const widgetName = _inferWidgetName(e.target);
    const currentPage = document.title
      ? document.title.replace(" – Custodian State Hub", "").trim()
      : (location.pathname.replace(/^\//, "") || "Overview");
    const pageName = inSidebar ? "Navigation" : currentPage;

    // Remove any open modal
    document.getElementById("_impr-root")?.remove();

    /* ── DOM construction ────────────────────────────────────────────── */
    const root = document.createElement("div");
    root.id = "_impr-root";
    root.className = "impr-modal";
    root.setAttribute("role", "dialog");
    root.setAttribute("aria-modal", "true");
    root.setAttribute("aria-label", "Request Improvement");

    const box = document.createElement("div");
    box.className = "impr-modal-box";

    // Header
    const header = document.createElement("div");
    header.className = "impr-header";
    const icon = Object.assign(document.createElement("span"), { className: "impr-header-icon", textContent: "💡" });
    const title = Object.assign(document.createElement("div"), { className: "impr-header-title", textContent: "Request Improvement" });
    const closeBtn = Object.assign(document.createElement("button"), { className: "impr-header-close", textContent: "✕ close" });
    header.append(icon, title, closeBtn);

    // Body
    const body = document.createElement("div");
    body.className = "impr-body";

    const ctxLabel = Object.assign(document.createElement("div"), { className: "impr-field-label", textContent: "Widget / Section" });
    const chip = Object.assign(document.createElement("div"), {
      className: "impr-context-chip",
      textContent: `${pageName}  ›  ${widgetName}`,
    });

    const sugLabel = Object.assign(document.createElement("div"), { className: "impr-field-label", textContent: "Your suggestion" });
    const textarea = document.createElement("textarea");
    textarea.className = "impr-textarea";
    textarea.placeholder = "Describe what you'd like to improve or change…";
    textarea.rows = 5;

    const hint = Object.assign(document.createElement("div"), {
      className: "impr-hint",
      textContent: "Ctrl + Enter to submit · Escape to cancel",
    });

    body.append(ctxLabel, chip, sugLabel, textarea, hint);

    // Footer
    const footer = document.createElement("div");
    footer.className = "impr-footer";
    const cancelBtn = Object.assign(document.createElement("button"), { className: "impr-btn impr-btn-cancel", textContent: "Cancel" });
    const submitBtn = Object.assign(document.createElement("button"), { className: "impr-btn impr-btn-submit", textContent: "Submit suggestion" });
    footer.append(cancelBtn, submitBtn);

    box.append(header, body, footer);
    root.append(box);
    document.body.append(root);

    // Focus textarea after animation settles
    setTimeout(() => textarea.focus(), 80);

    /* ── Close behaviour ─────────────────────────────────────────────── */
    const close = () => {
      root.remove();
      document.removeEventListener("keydown", onKey);
    };
    closeBtn.addEventListener("click", close);
    cancelBtn.addEventListener("click", close);
    root.addEventListener("click", e => { if (e.target === root) close(); });

    const onKey = e => {
      if (e.key === "Escape") close();
      if ((e.ctrlKey || e.metaKey) && e.key === "Enter") submitBtn.click();
    };
    document.addEventListener("keydown", onKey);

    /* ── Submit ──────────────────────────────────────────────────────── */
    submitBtn.addEventListener("click", async () => {
      const suggestion = textarea.value.trim();
      if (!suggestion) {
        textarea.classList.add("impr-error");
        textarea.focus();
        setTimeout(() => textarea.classList.remove("impr-error"), 1200);
        return;
      }

      submitBtn.disabled = true;
      submitBtn.textContent = "Submitting…";

      const location = `${pageName} › ${widgetName}`;
      const payload = {
        domain: domain,
        title: `UI: ${widgetName}`,
        description: suggestion,
        debt_type: "dashboard-improvement",
        severity: "low",
        status: "submitted",
        location,
      };

      try {
        const r = await fetch(`${apiBase}/technical-debt/`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify(payload),
        });
        if (r.ok) {
          close();
          _toast("✓ Suggestion saved — check UI Feedback in the nav");
        } else {
          submitBtn.disabled = false;
          submitBtn.textContent = "Submit suggestion";
          _toast(`⚠ Submission failed (HTTP ${r.status})`);
        }
      } catch {
        submitBtn.disabled = false;
        submitBtn.textContent = "Submit suggestion";
        _toast("⚠ API unreachable — submission failed");
      }
    });
  });
}
