// monitorProject.js
// Scope: project tab/header/card/selector display and project switch requests.
// Does not own project.json editing; projectOutline.js owns that.
// Does not own switch splash transition; projectSwitch.js owns that.

(() => {
  "use strict";

  function byId(id) { return document.getElementById(id); }
  function esc(value) {
    return String(value ?? "")
      .replace(/&/g, "&amp;")
      .replace(/</g, "&lt;")
      .replace(/>/g, "&gt;")
      .replace(/\"/g, "&quot;");
  }
  function toastMsg(message) { try { window.toast?.(message); } catch {} }
  function appendLog(text, tone = "neutral") { try { window.appendLog?.(text, tone); } catch {} }
  function activateTab(tabName) { try { window.activateTab?.(tabName); } catch {} }
  async function apiCall(path, method = "GET", body = null) {
    if (typeof window.api === "function") return await window.api(path, method, body);
    const opts = { method, headers: {} };
    if (body !== null) {
      opts.headers["Content-Type"] = "application/json";
      opts.body = JSON.stringify(body);
    }
    try {
      const res = await fetch(path, opts);
      return await res.json();
    } catch (err) {
      return { ok: false, error: err?.message || String(err) };
    }
  }

  async function notifyProjectSelect(projectOrName) {
    const input = projectOrName && typeof projectOrName === "object" ? projectOrName : { name: projectOrName };
    const name = String(input.name || "").trim();
    const serialNo = String(input.serialNo || input.id || "").trim();
    const key = serialNo || name;
    if (!key) return;

    if (!window.DeckProject?.initiateProjectSwitch) {
      toastMsg("Project switch controller unavailable");
      return;
    }

    await window.DeckProject.initiateProjectSwitch({
      name,
      serialNo,
      label: name || serialNo,
      source: input.source || "monitor-explicit"
    });
  }

  async function loadProjectSelector() {
    const result = await window.ProjectRegistry?.load?.();
    const select = byId("project-select");
    if (!select || !result) return;

    const projects = Array.isArray(result.projects) ? result.projects : [];
    const activeProject = result.projectMode === "project" ? String(result.activeProject || result.projectName || "").trim() : "";

    select.innerHTML = "";
    const placeholder = document.createElement("option");
    placeholder.value = "";
    placeholder.textContent = result.isBackstage ? "System" : "Select project";
    placeholder.disabled = true;
    placeholder.selected = !activeProject;
    select.appendChild(placeholder);

    await renderProjectCards(projects, activeProject);

    for (const p of projects) {
      const name = String(p?.name || "").trim();
      const lower = name.toLowerCase();
      if (!name || lower === "system" || lower === "backstage" || lower === "universal") continue;
      const opt = document.createElement("option");
      opt.dataset.serialNo = String(p?.serialNo || "").trim();
      opt.value = name;
      opt.textContent = name;
      select.appendChild(opt);
    }

    if (activeProject && [...select.options].some(opt => opt.value === activeProject)) select.value = activeProject;
    else select.value = "";

    if (!byId("project-select-apply-btn")) {
      const snapProjectSelectToCurrent = async () => {
        const latest = await window.ProjectRegistry?.load?.();
        const currentProject = latest?.projectMode === "project" ? String(latest?.activeProject || latest?.projectName || "").trim() : "";
        if (select && select.value !== currentProject && [...select.options].some(opt => opt.value === currentProject)) select.value = currentProject;
      };

      select.insertAdjacentHTML("afterend", '<button id="project-select-apply-btn" class="inp-btn" title="Switch project">✓</button>');
      byId("project-select-apply-btn")?.addEventListener("click", async () => {
        const selectedOption = select.selectedOptions?.[0] || null;
        const next = String(select.value || "").trim();
        const serialNo = String(selectedOption?.dataset?.serialNo || "").trim();
        if (!next && !serialNo) return;
        const latest = await window.ProjectRegistry?.load?.();
        const currentProject = latest?.projectMode === "project" ? String(latest?.activeProject || latest?.projectName || "").trim() : "";
        if (next === currentProject) return;
        await notifyProjectSelect({ name: next, serialNo, source: "monitor-dropdown" });
      });

      window.snapProjectSelectToCurrent = snapProjectSelectToCurrent;
    }
  }

  async function renderProjectCards(projects, activeProject) {
    const strip = byId("project-card-strip");
    if (!strip) return;
    strip.innerHTML = "";

    const realProjects = (projects || []).filter(p => {
      const name = String(p?.name || "").trim().toLowerCase();
      return name && name !== "system" && name !== "backstage" && name !== "universal";
    });

    const latestByProject = new Map();
    const tapeData = await apiCall("/playback");
    const tapeItems = Array.isArray(tapeData?.tape) ? tapeData.tape : [];

    const normalize = value => String(value || "").trim().toLowerCase().replace(/\\/g, "/");
    const getProjectKey = project => normalize(project?.name);
    const projectMatches = (project, tapeProject, filePath) => {
      const key = getProjectKey(project);
      const tp = normalize(tapeProject);
      const fp = normalize(filePath);
      const projectPath = normalize(project?.location || project?.path);
      return Boolean(key && (
        tp === key ||
        fp.includes(`/projects/${key}`) ||
        fp.includes(`projects/${key}`) ||
        (projectPath && fp.includes(projectPath))
      ));
    };

    for (let i = tapeItems.length - 1; i >= 0; i--) {
      const item = tapeItems[i] || {};
      if (item.status !== "done") continue;
      const manifest = item.manifest || {};
      const result = item.result || {};
      const filePath = String(manifest.FilePath || result.filePath || "").trim();
      const action = String(manifest.Action || result.action || "").trim();
      const task = String(manifest.Task || result.task || "").trim();
      const tapeProject = String(item.project || result.project || "").trim();
      if (!filePath && !action && !task) continue;
      const date = item.timestamp ? new Date(item.timestamp).toLocaleDateString() : "";
      const fileName = filePath ? filePath.replace(/\\/g, "/").split("/").pop() : "";
      const summary = task || [action || "RUN", fileName ? `(${fileName})` : ""].filter(Boolean).join(" ");
      for (const project of realProjects) {
        const key = getProjectKey(project);
        if (!key || latestByProject.has(key)) continue;
        if (projectMatches(project, tapeProject, filePath)) latestByProject.set(key, { task: summary, date });
      }
      if (latestByProject.size >= realProjects.length) break;
    }

    const settings = await window.SettingsStore?.load?.() || {};
    const accessTier = String(settings.authTier || "limited").toLowerCase();
    const limitedAccess = accessTier === "limited";
    const displayProjects = limitedAccess ? realProjects.slice(0, 2) : realProjects;
    const visibleCount = Math.max(4, displayProjects.length);

    for (let index = 0; index < visibleCount; index++) {
      const project = displayProjects[index];
      const lockedProjectSlot = limitedAccess && index >= 2 && index < 4;
      const accent = (index % 4) + 1;
      const card = document.createElement("button");
      card.className = "project-card";
      card.dataset.projectAccent = String(accent);
      if (project) {
        card.dataset.projectSerial = String(project.serialNo || "").trim();
        card.dataset.projectName = String(project.name || "").trim();
      }

      if (lockedProjectSlot) {
        card.classList.add("locked-project-card");
        card.innerHTML = `
          <div class="project-card-title">🔒 Subscribe to Unlock</div>
          <div class="project-card-task">Unlimited unlocks more projects</div>
          <div class="project-card-date">Project slot ${index + 1}</div>
        `;
        card.addEventListener("click", () => { activateTab("settings"); toastMsg("Upgrade to unlock more project slots"); });
      } else if (project) {
        const latest = latestByProject.get(getProjectKey(project)) || null;
        const taskLabel = latest?.task || "no recent activity";
        const dateLabel = latest?.date || "";
        card.innerHTML = `
          <div class="project-card-title">${esc(project.name)}</div>
          <div class="project-card-task">${esc(taskLabel)}</div>
          <div class="project-card-date">${esc(dateLabel)}</div>
        `;
        card.addEventListener("click", async () => await notifyProjectSelect(project));
      } else {
        card.classList.add("create-project-card");
        card.innerHTML = `
          <div class="project-card-title">ADD PROJECT</div>
          <div class="project-card-task">Create new workspace</div>
          <div class="project-card-date">Click to begin</div>
        `;
        card.addEventListener("click", () => byId("project-create-btn")?.click());
      }
      strip.appendChild(card);
    }
  }

  function renderProject(projectState = null) {
    const pd = projectState && typeof projectState === "object" ? projectState : null;
    if (!pd) return;
    const select = byId("project-select");
    const info = byId("project-info");
    const color = pd?.color || {};
    const isSystem = Boolean(pd?.isBackstage) || pd?.source === "system" || pd?.projectMode === "system";
    const selectedName = String(pd?.name || pd?.activeProject || pd?.project?.name || "").trim();
    const displayName = isSystem ? "System" : (selectedName || "PROJECT SELECT");
    const summary = isSystem ? String(pd?.summary || "System root project").trim() : String(pd?.summary || pd?.project?.summary || pd?.project?.description || "No project loaded").trim();

    if (select && !isSystem && selectedName && select.value !== selectedName && [...select.options].some(opt => opt.value === selectedName)) {
      select.value = selectedName;
    }

    const setTxt = (id, v) => { const el = byId(id); if (el) el.textContent = v || ""; };
    setTxt("project-title", displayName);
    setTxt("project-summary", isSystem ? summary : summary);

    if (info) info.classList.toggle("backstage", isSystem);
    if (color.primary && info) info.style.setProperty("--active-project-primary", color.primary);
    if (color.dark && info) info.style.setProperty("--active-project-dark", color.dark);
    if (color.light && info) info.style.setProperty("--active-project-light", color.light);

    const accent = Number.isFinite(Number(pd?.accentIndex)) ? String(Number(pd.accentIndex) + 1) : String(pd?.projectAccent || "1");
    document.body.dataset.projectAccent = isSystem ? "0" : accent;
  }

  function isVisibleElement(el) {
    if (!el) return false;
    return Boolean(el.offsetParent !== null || el.classList.contains("selected"));
  }
  function elementTextForSelection(el) {
    if (!el) return "";
    const label = el.getAttribute("aria-label") || el.dataset?.contextLabel || el.placeholder || el.name || el.id || "";
    const value = "value" in el ? String(el.value || "").trim() : String(el.innerText || el.textContent || "").trim();
    return [label, value].filter(Boolean).join(label && value ? ": " : "").trim();
  }
  function getProjectSelectableUnits() {
    const selectors = [
      "#proj-name", "#proj-location", "#proj-summary", "#proj-notes",
      "#project-title", "#project-summary",
      "#project-select", "#project-card-strip .project-card",
      ".project-list-section", ".project-list-title-input",
      ".project-list-section .field-input", ".project-list-section .field-textarea"
    ];
    const seen = new Set();
    return selectors.flatMap(selector => [...document.querySelectorAll(selector)])
      .filter(el => {
        if (seen.has(el)) return false;
        seen.add(el);
        return isVisibleElement(el) && elementTextForSelection(el);
      });
  }
  function clearContextSelections() {
    document.querySelectorAll(".context-selected, .selected-project-unit").forEach(item => item.classList.remove("context-selected", "selected-project-unit"));
  }
  function selectProjectUnit(el) {
    clearContextSelections();
    if (!el) return;
    el.classList.add("context-selected", "selected-project-unit");
    if (typeof el.focus === "function" && /input|textarea|select|button/i.test(el.tagName || "")) el.focus({ preventScroll: true });
    el.scrollIntoView({ block: "nearest", behavior: "smooth" });
  }
  function navigateProject(direction) {
    const items = getProjectSelectableUnits();
    if (!items.length) return window.navigateLogGroups?.(direction);
    const current = Number(window.selectedProjectUnitIndex ?? -1);
    const next = typeof window.clamp === "function" ? window.clamp(current, items.length, direction) : (current + direction + items.length) % items.length;
    window.selectedProjectUnitIndex = next;
    selectProjectUnit(items[next]);
  }

  window.MonitorProject = {
    loadProjectSelector,
    renderProject,
    notifyProjectSelect,
    renderProjectCards,
    getProjectSelectableUnits,
    navigateProject
  };
})();
