// 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 isBackstageSystem = Boolean(result.isBackstage) && (result.projectMode === "system" || String(result.projectSerial || "") === "system");
    const isSystemMessages = !isBackstageSystem && result.projectMode !== "project";
    const activeProject = isBackstageSystem ? "System" : isSystemMessages ? String(result.activeProject || result.projectName || "").trim() : result.projectMode === "project" ? String(result.activeProject || result.projectName || "").trim() : "";

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

    if (result.isBackstage) {
      const systemOption = document.createElement("option");
      systemOption.value = "System";
      systemOption.dataset.serialNo = "system";
      systemOption.textContent = "System";
      select.appendChild(systemOption);
    }

    if (isSystemMessages && activeProject) {
      const welcomeOption = document.createElement("option");
      welcomeOption.value = activeProject;
      welcomeOption.dataset.serialNo = "";
      welcomeOption.textContent = activeProject;
      welcomeOption.disabled = true;
      welcomeOption.selected = true;
      select.appendChild(welcomeOption);
    }

    await renderProjectCards(projects, activeProject);
    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 = Boolean(latest?.isBackstage) && (latest?.projectMode === "system" || String(latest?.projectSerial || "") === "system") ? "System" : latest?.projectMode !== "project" ? String(latest?.activeProject || latest?.projectName || "").trim() : 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 = Boolean(latest?.isBackstage) && (latest?.projectMode === "system" || String(latest?.projectSerial || "") === "system") ? "System" : latest?.projectMode !== "project" ? String(latest?.activeProject || latest?.projectName || "").trim() : 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-carousel") || 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 projectAliases = project => Array.from(new Set([project?.serialNo, project?.id, project?.name, project?.location, project?.path].map(normalize).filter(Boolean)));
    const getProjectKey = project => normalize(project?.serialNo || project?.id || project?.name);
    const projectMatches = (project, tapeProject, filePath, projectSerial = "") => {
      const tp = normalize(tapeProject);
      const fp = normalize(filePath);
      const ps = normalize(projectSerial);
      return projectAliases(project).some(alias => Boolean(alias && (
        tp === alias ||
        ps === alias ||
        fp.includes(`/projects/${alias}`) ||
        fp.includes(`projects/${alias}`) ||
        fp.includes(alias)
      )));
    };

    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();
      const tapeSerial = String(item.projectSerial || result.projectSerial || "").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, tapeSerial)) latestByProject.set(key, { task: summary, date });
      }
      if (latestByProject.size >= realProjects.length) break;
    }

    if (latestByProject.size < realProjects.length) {
      const logData = await apiCall("/logs/system?limit=2000");
      const lines = Array.isArray(logData?.lines) ? logData.lines : [];
      for (let i = lines.length - 1; i >= 0; i--) {
        const line = String(lines[i] || "");
        if (!line.includes("execute_done") || !line.includes("status:done") || !line.includes("Task:")) continue;
        const date = (line.match(/^(\d{4}-\d{2}-\d{2})\s+\d{2}:\d{2}:\d{2}/) || [])[1] || "";
        const task = (line.match(/\bTask:(.+)$/) || [])[1]?.trim() || "Recorded code change";
        const filePath = (line.match(/\bfilePath:([^\s]+)/) || [])[1] || "";
        const serial = (line.match(/\bserial:([^\s]+)/) || [])[1] || "";
        const logProject = (line.match(/\bproject:([^\s]+)/) || [])[1] || "";
        for (const project of realProjects) {
          const key = getProjectKey(project);
          if (!key || latestByProject.has(key)) continue;
          if (projectMatches(project, logProject, filePath, serial)) latestByProject.set(key, { task, 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 = limitedAccess ? 4 : Math.max(4, displayProjects.length + 1);

    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();
      }
      const projectName = String(project?.name || "").trim();
      const projectSerial = String(project?.serialNo || project?.id || "").trim();
      const activeKey = String(activeProject || "").trim().toLowerCase();
      if (project && activeKey && (projectName.toLowerCase() === activeKey || projectSerial.toLowerCase() === activeKey)) card.classList.add("active");

      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-display") || byId("project-info");
    const color = pd?.color || {};
    const isBackstageSystem = Boolean(pd?.isBackstage) || String(pd?.projectSerial || "") === "system";
    const isSystemMessages = !isBackstageSystem && (pd?.source === "system-messages" || pd?.projectMode === "project_select");
    const isSystem = isBackstageSystem || isSystemMessages;
    const selectedName = String(pd?.name || pd?.activeProject || pd?.project?.name || "").trim();
    const displayName = isBackstageSystem ? "System" : isSystemMessages ? (selectedName || "Nodarama Verbatim") : (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 || ""; el.dataset.reflect = v || ""; } };
    setTxt("project-title", displayName);
    setTxt("project-summary", isSystem ? summary : summary);

    if (info) info.classList.toggle("backstage", isBackstageSystem);
    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-summary", "#proj-notes",
      "#project-title", "#project-summary",
      "#project-select", "#project-carousel .project-card", "#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]);
  }

  async function renderCustomProjectSettingsList(settings = null) {
    const host = byId("set-custom-projects-list");
    if (!host) return;
    const data = settings || await window.SettingsStore?.load?.();
    const customProjects = Array.isArray(data?.customProjects) ? data.customProjects : [];
    host.innerHTML = "";
    if (!customProjects.length) {
      host.innerHTML = '<div style="font-size:11px;color:var(--text2)">No custom project folders registered.</div>';
      return;
    }
    customProjects.forEach(item => {
      const row = document.createElement("div");
      row.style.cssText = "display:grid;gap:2px;padding:7px;border:1px solid var(--border);border-radius:var(--radius);background:var(--bg2);font-size:11px";
      row.innerHTML = `<div style="color:var(--text)">${esc(item.name || "Custom Project")}</div><div style="color:var(--text2);word-break:break-word">${esc(item.location || "")}</div>`;
      host.appendChild(row);
    });
  }

  async function addCustomProjectFromSettings() {
    const nameInput = byId("set-custom-project-name");
    const pathInput = byId("set-custom-project-path");
    const button = byId("set-custom-project-add-btn");
    const name = String(nameInput?.value || "").trim();
    const location = String(pathInput?.value || "").trim();
    if (!name || !location) {
      toastMsg("Enter a custom project name and folder path");
      return;
    }
    if (button) button.disabled = true;
    const result = await window.ProjectRegistry?.addCustom?.(name, location);
    if (button) button.disabled = false;
    if (!result?.ok) {
      toastMsg(result?.message || result?.error || "Custom project registration failed");
      appendLog(`✗ custom project failed: ${result?.message || result?.error || "unknown"}`, "fail");
      return;
    }
    if (nameInput) nameInput.value = "";
    if (pathInput) pathInput.value = "";
    toastMsg("Custom project registered");
    appendLog(`✓ custom project registered: ${result.project?.name || name}`, "pass");
    await renderCustomProjectSettingsList();
    await loadProjectSelector();
  }

  function bindCustomProjectSettingsControls() {
    const button = byId("set-custom-project-add-btn");
    if (!button || button.dataset.customProjectBound === "true") return;
    button.dataset.customProjectBound = "true";
    button.addEventListener("click", addCustomProjectFromSettings);
    renderCustomProjectSettingsList();
  }

  function bindAmpSetupButton() {
    const button = byId("copy-amp-action-script-btn");
    if (!button || button.dataset.ampSetupBound === "true") return;
    button.dataset.ampSetupBound = "true";
    button.addEventListener("click", () => {
      const url = "https://nodarama.com/resources/ngrok-custom-gpt-setup.html";
      window.open(url, "_blank", "noopener");
      toastMsg("Opening AMP setup");
      appendLog("↗ AMP setup opened", "neutral");
    });
  }

  bindAmpSetupButton();
  bindCustomProjectSettingsControls();

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