// ── Symframe AWAITING surface ───────────────────────────────────────────────
// Stage C of the Dynamic Glass Panel arc — see ~/Documents/dynamic-glass-panel.md.
//
// The AWAITING surface is a footer inside the symframe that merges
// in-flight sub-agents and scheduled cron jobs into a single list —
// one mental concept: "things that aren't done yet."
//
// Sort order:
//   1. In-flight sub-agents first, sorted by start time (descending —
//      most-recently-started visible at the top)
//   2. Then scheduled jobs sorted by next ETA (soonest first)
//
// Data flow:
//   subagents.js + scheduling.js dispatch CustomEvents after each
//   successful poll fetch. The AWAITING surface listens to both events
//   and re-renders the merged list. No duplicate polling — single
//   source of truth per data type.
//
// Click handlers:
//   - Sub-agent row → no-op for now (subagents.list returns enough
//     info to display, but there's no per-subagent detail modal yet;
//     future enhancement: open a side view with the subagent transcript)
//   - Schedule row → opens the existing schedule edit modal via
//     window.schedulingPanel.openForEdit(job)
//   - Schedule toggle → window.schedulingPanel.toggle(jobId)
//   - [+ Add] → small menu: "Spawn subagent" / "Add scheduled task"
//     → opens the corresponding existing modal.
// ─────────────────────────────────────────────────────────────────────────────

"use strict";

(function () {
  const root = document.getElementById("symframe-awaiting");
  if (!root) {
    return;
  }
  const list = document.getElementById("awaiting-list");
  const countEl = document.getElementById("awaiting-count");
  const addBtn = document.getElementById("awaiting-add-btn");
  const addMenu = document.getElementById("awaiting-add-menu");

  // ── State ──
  let subagents = [];
  let schedules = [];

  // ── DOM helpers ──
  function escHtml(s) {
    return String(s ?? "")
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/"/g, "&quot;")
      .replace(/'/g, "&#39;");
  }

  // ── Formatters ──
  function formatRuntime(sub) {
    const start = sub.startedAt;
    const end = sub.endedAt || Date.now();
    if (!start) {
      return "--";
    }
    const seconds = Math.floor((end - start) / 1000);
    if (seconds < 60) {
      return `${seconds}s`;
    }
    const minutes = Math.floor(seconds / 60);
    const secs = seconds % 60;
    if (minutes < 60) {
      return `${minutes}m${secs > 0 ? secs + "s" : ""}`;
    }
    const hours = Math.floor(minutes / 60);
    const mins = minutes % 60;
    return `${hours}h${mins}m`;
  }

  function formatEta(nextRunAtMs) {
    if (!nextRunAtMs) {
      return "—";
    }
    const ms = nextRunAtMs - Date.now();
    if (ms <= 0) {
      return "now";
    }
    const minutes = Math.floor(ms / 60_000);
    if (minutes < 1) {
      return "<1m";
    }
    if (minutes < 60) {
      return `in ${minutes}m`;
    }
    const hours = Math.floor(minutes / 60);
    const mins = minutes % 60;
    if (hours < 24) {
      return mins > 0 ? `in ${hours}h ${mins}m` : `in ${hours}h`;
    }
    const days = Math.floor(hours / 24);
    const hrs = hours % 24;
    return hrs > 0 ? `in ${days}d ${hrs}h` : `in ${days}d`;
  }

  // ── Item builders ──
  function buildSubagentRow(sub) {
    const item = document.createElement("div");
    item.className = "awaiting-item awaiting-item-subagent";
    item.dataset.runId = sub.runId || "";
    const label = sub.label || "Subagent";
    const status = sub.status === "active" || !sub.endedAt ? "running" : sub.status;
    const right = status === "running" ? formatRuntime(sub) : status;
    item.innerHTML = `
      <span class="awaiting-glyph awaiting-glyph-subagent">◆</span>
      <span class="awaiting-label">${escHtml(label)}</span>
      <span class="awaiting-meta">${escHtml(right)}</span>
    `;
    return item;
  }

  function buildScheduleRow(job) {
    const item = document.createElement("div");
    item.className = "awaiting-item awaiting-item-schedule";
    if (!job.enabled) {
      item.classList.add("awaiting-item-disabled");
    }
    item.dataset.scheduleId = job.id || "";
    item.tabIndex = 0;
    item.setAttribute("role", "button");
    const name = job.name || "Unnamed";
    const eta = job.enabled ? formatEta(job.state?.nextRunAtMs) : "off";
    item.innerHTML = `
      <span class="awaiting-glyph awaiting-glyph-schedule" data-action="toggle" title="${job.enabled ? "Disable" : "Enable"}">⏱</span>
      <span class="awaiting-label">${escHtml(name)}</span>
      <span class="awaiting-meta">${escHtml(eta)}</span>
    `;
    // Toggle on the glyph; edit modal on the row.
    item.addEventListener("click", (e) => {
      if (e.target instanceof Element && e.target.dataset.action === "toggle") {
        e.stopPropagation();
        if (typeof window.schedulingPanel?.toggle === "function") {
          void window.schedulingPanel.toggle(job.id);
        }
        return;
      }
      if (typeof window.schedulingPanel?.openForEdit === "function") {
        window.schedulingPanel.openForEdit(job);
      }
    });
    item.addEventListener("keydown", (e) => {
      if (e.key === "Enter" || e.key === " ") {
        e.preventDefault();
        if (typeof window.schedulingPanel?.openForEdit === "function") {
          window.schedulingPanel.openForEdit(job);
        }
      }
    });
    return item;
  }

  // ── Render ──
  // Stage C.1 fix: the AWAITING footer is ALWAYS visible — it's a
  // permanent part of the panel's identity (matches the §5 spec
  // "always-present footer"). When nothing's pending, an empty-state
  // placeholder appears so the user always sees the surface, the
  // [+ Add] button, and the implicit "this is where deferred work
  // shows up" affordance.
  function render() {
    const activeSubagents = subagents
      .filter((s) => s.status === "active" || !s.endedAt)
      .toSorted((a, b) => (b.startedAt || 0) - (a.startedAt || 0));

    const sortedSchedules = schedules.toSorted((a, b) => {
      // Enabled first; then by next ETA ascending; disabled tail
      if (a.enabled !== b.enabled) {
        return b.enabled ? 1 : -1;
      }
      return (a.state?.nextRunAtMs || Infinity) - (b.state?.nextRunAtMs || Infinity);
    });

    const totalActive = activeSubagents.length + sortedSchedules.filter((s) => s.enabled).length;

    // Count badge: "N active" (in-flight subagents + enabled schedules)
    // or "idle" when nothing's pending.
    if (countEl) {
      if (totalActive === 0) {
        countEl.textContent = "idle";
      } else {
        const subPart =
          activeSubagents.length > 0
            ? `${activeSubagents.length} sub${activeSubagents.length !== 1 ? "s" : ""}`
            : null;
        const schedPart =
          sortedSchedules.filter((s) => s.enabled).length > 0
            ? `${sortedSchedules.filter((s) => s.enabled).length} job${sortedSchedules.filter((s) => s.enabled).length !== 1 ? "s" : ""}`
            : null;
        countEl.textContent = [subPart, schedPart].filter(Boolean).join(" · ");
      }
    }

    if (!list) {
      return;
    }
    list.innerHTML = "";
    if (activeSubagents.length === 0 && sortedSchedules.length === 0) {
      const empty = document.createElement("div");
      empty.className = "awaiting-empty";
      empty.textContent = "Nothing pending — use [+ Add] to spawn a subagent or schedule a task.";
      list.appendChild(empty);
      return;
    }
    for (const sub of activeSubagents) {
      list.appendChild(buildSubagentRow(sub));
    }
    for (const job of sortedSchedules) {
      list.appendChild(buildScheduleRow(job));
    }
  }

  // ── Add menu ──
  let addMenuOpen = false;

  function openAddMenu() {
    if (!addMenu || !addBtn) {
      return;
    }
    addMenuOpen = true;
    addMenu.hidden = false;
    addBtn.setAttribute("aria-expanded", "true");
    document.addEventListener("click", onOutsideClickAddMenu, true);
    document.addEventListener("keydown", onAddMenuKey);
  }

  function closeAddMenu() {
    if (!addMenu || !addBtn) {
      return;
    }
    addMenuOpen = false;
    addMenu.hidden = true;
    addBtn.setAttribute("aria-expanded", "false");
    document.removeEventListener("click", onOutsideClickAddMenu, true);
    document.removeEventListener("keydown", onAddMenuKey);
  }

  function onOutsideClickAddMenu(e) {
    if (!addMenu || !addBtn) {
      return;
    }
    if (e.target instanceof Node) {
      if (addMenu.contains(e.target) || addBtn.contains(e.target)) {
        return;
      }
    }
    closeAddMenu();
  }

  function onAddMenuKey(e) {
    if (e.key === "Escape") {
      closeAddMenu();
    }
  }

  // ── Init ──
  function init() {
    window.addEventListener("symi:subagents-updated", (e) => {
      subagents = e.detail?.subagents || [];
      render();
    });
    window.addEventListener("symi:schedules-updated", (e) => {
      schedules = e.detail?.schedules || [];
      render();
    });

    if (addBtn) {
      addBtn.addEventListener("click", (e) => {
        e.stopPropagation();
        if (addMenuOpen) {
          closeAddMenu();
        } else {
          openAddMenu();
        }
      });
    }
    if (addMenu) {
      addMenu.addEventListener("click", (e) => {
        const target = e.target instanceof Element ? e.target.closest("[data-add]") : null;
        if (!target) {
          return;
        }
        const which = target.getAttribute("data-add");
        closeAddMenu();
        if (which === "subagent" && typeof window.subagentsPanel?.open === "function") {
          window.subagentsPanel.open();
        } else if (which === "schedule" && typeof window.schedulingPanel?.open === "function") {
          window.schedulingPanel.open();
        }
      });
    }

    // First paint
    render();
  }

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