// Dedicated views for Intake / Tasks / Queue.
// Wired to real API via window.LHData (data.jsx).

const { useState: useStateX, useMemo: useMemoX, useEffect: useEffectX } = React;
const { PROJECTS: PROJECTS_X, fetchIntake: fetchIntakeX, fetchTasks: fetchTasksX, fetchAllQueue: fetchAllQueueX, fetchSessions: fetchSessionsX, usePolling: usePollingX, postIntake: postIntakeX, patchQueueItem: patchQueueItemX, deleteQueueItem: deleteQueueItemX } = window.LHData;

// ---- shared helpers ----
function StageTagX({ s }) {
  const labels = {
    idea: "Idea", dispatched: "Dispatched", working: "Working", done: "Done", blocked: "Blocked",
    pending: "Pending", claimed: "Claimed", sent: "Sent", cancelled: "Cancelled",
    idle: "Idle", silent: "Silent", stuck: "Stuck",
  };
  return <span className={"stage stage-" + s}>{labels[s] || s}</span>;
}
function RowX({ children, onClick, active, className }) {
  const cls = "row" + (className ? " " + className : "");
  return <div className={cls} onClick={onClick} style={active ? {borderColor:"var(--accent)", background:"var(--surface)"} : null}>{children}</div>;
}

// Module-scoped Set so the 5s polling re-render keeps expanded rows
// expanded. Mirrors lib/dashboard.js#toggleExpandedSet semantics
// (the lib version is unit-tested under node:test; this side is for
// the Babel-standalone browser bundle that can't import lib/).
const _intakeExpandedRows = new Set();
function _isIntakeRowExpandable(rawText) {
  return typeof rawText === "string" && rawText.trim().length > 0;
}
function _toggleIntakeExpanded(id) {
  if (typeof id !== "string" || id === "") return;
  if (_intakeExpandedRows.has(id)) _intakeExpandedRows.delete(id);
  else _intakeExpandedRows.add(id);
}

// Format timestamps
function timeAgoX(dateStr) {
  if (!dateStr) return "";
  const d = new Date(dateStr);
  if (isNaN(d.getTime())) return dateStr;
  const now = Date.now();
  const diff = now - d.getTime();
  if (diff < 0) return "just now";
  const secs = Math.floor(diff / 1000);
  if (secs < 60) return secs <= 5 ? "just now" : `${secs}s ago`;
  const mins = Math.floor(secs / 60);
  if (mins < 60) return `${mins}m ago`;
  const hours = Math.floor(mins / 60);
  if (hours < 24) return `${hours}h ago`;
  const days = Math.floor(hours / 24);
  return `${days}d ago`;
}

// =============== ProjectPick ===============
function ProjectPick({ value, onChange }) {
  const [open, setOpen] = useStateX(false);
  const ref = React.useRef(null);
  React.useEffect(() => {
    if (!open) return;
    const onDoc = (e) => { if (!ref.current?.contains(e.target)) setOpen(false); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [open]);
  return (
    <div className="project-pick-wrap" ref={ref}>
      <button
        type="button"
        className="project-pick"
        onClick={() => setOpen(o => !o)}
        aria-expanded={open}
        aria-haspopup="listbox"
      >
        <span className="proj">{value}</span>
        <span className="chev"><I.Chev/></span>
      </button>
      {open && (
        <div className="project-pick-menu" role="listbox">
          {PROJECTS_X.map(p => (
            <button
              key={p.id}
              type="button"
              className={"project-pick-item" + (value === p.id ? " active" : "")}
              onClick={() => { onChange(p.id); setOpen(false); }}
            >
              <span className="project-pick-dot" style={{background: `oklch(0.78 0.13 ${p.color})`}}></span>
              <span className="project-pick-name">{p.id}</span>
              <span className="project-pick-short">{p.short}</span>
            </button>
          ))}
        </div>
      )}
    </div>
  );
}

// =============== Intake (dedicated) ===============
function IntakeView({ onSelect, selectedId, project, setProject, draft, setDraft, onSubmit, filterProj, setFilterProj, intake, refreshIntake }) {
  const [filter, setFilter] = useStateX("open"); // open | all | done
  // Force re-render after toggling the module-scoped expanded Set.
  const [, _bumpExpandTick] = useStateX(0);
  const onToggleExpand = (id) => {
    _toggleIntakeExpanded(id);
    _bumpExpandTick(n => n + 1);
  };
  const [collapsedProjects, setCollapsedProjects] = useStateX(() => {
    try { return JSON.parse(localStorage.getItem("lh.intake.collapsed") || "{}"); }
    catch { return {}; }
  });
  useEffectX(() => {
    try { localStorage.setItem("lh.intake.collapsed", JSON.stringify(collapsedProjects)); } catch {}
  }, [collapsedProjects]);
  const toggleProject = (proj) => setCollapsedProjects(p => ({ ...p, [proj]: !p[proj] }));

  const allIntake = intake || [];

  const list = useMemoX(() => {
    let all = allIntake;
    if (filterProj && filterProj !== "__all") all = all.filter(i => i.project === filterProj);
    if (filter === "open") return all.filter(i => i.stage === "idea");
    if (filter === "done") return all.filter(i => i.stage === "done");
    return all;
  }, [filter, filterProj, allIntake]);

  const grouped = useMemoX(() => {
    const m = new Map();
    for (const i of list) {
      if (!m.has(i.project)) m.set(i.project, []);
      m.get(i.project).push(i);
    }
    return [...m.entries()];
  }, [list]);

  const counts = {
    open: allIntake.filter(i=>i.stage==="idea").length,
    all:  allIntake.length,
    done: allIntake.filter(i=>i.stage==="done").length,
  };

  const handleSubmit = async () => {
    if (!draft.trim()) return;
    try {
      await postIntakeX({ project, raw_text: draft });
      setDraft("");
      if (refreshIntake) refreshIntake();
    } catch (err) {
      console.error("Failed to submit intake:", err);
    }
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <div className="page-title">Intake</div>
          <div className="page-sub">capture - {counts.open} open - {counts.done} done</div>
        </div>
        <div className="page-actions">
          <div className="seg">
            <button className={"seg-btn"+(filter==="open"?" on":"")} onClick={()=>setFilter("open")}>Open <span className="cnt">{counts.open}</span></button>
            <button className={"seg-btn"+(filter==="all"?" on":"")}  onClick={()=>setFilter("all")}>All <span className="cnt">{counts.all}</span></button>
            <button className={"seg-btn"+(filter==="done"?" on":"")} onClick={()=>setFilter("done")}>Done <span className="cnt">{counts.done}</span></button>
          </div>
          {setFilterProj && <window.ProjectFilter value={filterProj} onChange={setFilterProj} intake={allIntake}/>}
        </div>
      </div>

      <div className="intake-layout">
        {/* Capture pane (left) */}
        <div className="col" style={{height:"fit-content", maxHeight:"100%"}}>
          <div className="col-head">
            <span className="col-title">Capture</span>
            <span className="col-count">Enter to submit</span>
          </div>
          <div className="capture">
            <div className="label">Project</div>
            <ProjectPick value={project} onChange={setProject}/>
            <div className="label">Idea</div>
            <textarea
              value={draft}
              onChange={e => setDraft(e.target.value)}
              onKeyDown={e => {
                if (e.key === "Enter" && !e.shiftKey && !e.isComposing && draft.trim()) {
                  e.preventDefault();
                  handleSubmit();
                }
              }}
              placeholder={"First line becomes the section title.\nShift+Enter for a new line.\n\nMarkdown ok -- ## headings, [[wikilinks]], etc."}
              style={{minHeight: 240}}
            />
            <div className="capture-foot">
              <span className="capture-hint">{draft.length} chars</span>
              <button className="btn btn-accent" onClick={handleSubmit} disabled={!draft.trim()}>
                Submit <span className="kbd">&crarr;</span>
              </button>
            </div>
          </div>
        </div>

        {/* Idea list (right) */}
        <div className="col">
          <div className="col-head">
            <span className="col-title">Ideas - {filter}</span>
            <span className="col-count">{list.length} items</span>
          </div>
          <div className="col-body intake-groups">
            {list.length === 0 && <div className="empty">no items</div>}
            {grouped.map(([proj, items]) => {
              const collapsed = !!collapsedProjects[proj];
              const projMeta = PROJECTS_X.find(p => p.id === proj);
              return (
                <div key={proj} className={"proj-group" + (collapsed ? " collapsed" : "")}>
                  <div className="proj-group-head" onClick={() => toggleProject(proj)}>
                    <button
                      className="proj-group-chevron"
                      aria-label={collapsed ? "Expand" : "Collapse"}
                      onClick={(e) => { e.stopPropagation(); toggleProject(proj); }}
                    >
                      <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                        <path d="M3 2L7 5L3 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
                      </svg>
                    </button>
                    <span className="proj-group-name">{proj}</span>
                    <span className="proj-group-count">{items.length}{projMeta ? " - " + projMeta.short : ""}</span>
                  </div>
                  {!collapsed && (
                    <div className="proj-group-body">
                      {items.map(i => {
                        const expandable = _isIntakeRowExpandable(i.raw_text);
                        const expanded = _intakeExpandedRows.has(i.id);
                        const rowClass =
                          (expandable ? "intake-row-expandable" : "intake-row-inert") +
                          (expanded ? " intake-row-expanded" : "");
                        return (
                          <React.Fragment key={i.id}>
                            <RowX
                              active={selectedId===i.id}
                              onClick={expandable ? () => onToggleExpand(i.id) : undefined}
                              className={rowClass}
                            >
                              <span className="id">{i.id}</span>
                              <span className="ago">{timeAgoX(i.created_at)}</span>
                              <div className="title">{(i.raw_text||"").replace(/^##\s*/, "").slice(0, 110)}{(i.raw_text||"").length>110?"...":""}</div>
                              <div className="meta">
                                <StageTagX s={i.stage}/>
                                {i.analysis && <span style={{fontFamily:"var(--mono)", fontSize:10, color:"var(--info)"}}>analysed</span>}
                              </div>
                            </RowX>
                            {expanded && (
                              <div className="intake-detail-row" data-intake-id={i.id}>
                                <div className="intake-detail-section">
                                  <div className="intake-detail-label">Raw text</div>
                                  <div className="intake-detail-body">{i.raw_text}</div>
                                </div>
                                {i.analysis && (
                                  <div className="intake-detail-section">
                                    <div className="intake-detail-label">Analysis</div>
                                    <div className="intake-detail-body">{i.analysis}</div>
                                  </div>
                                )}
                              </div>
                            )}
                          </React.Fragment>
                        );
                      })}
                    </div>
                  )}
                </div>
              );
            })}
          </div>
        </div>
      </div>
    </div>
  );
}

// =============== Tasks (dedicated) ===============
function TasksView({ onSelect, selectedId, filterProj, setFilterProj, tasks }) {
  const [stage, setStage] = useStateX("live"); // live | done | all
  const allTasks = tasks || [];

  const list = useMemoX(() => {
    let base = allTasks;
    if (filterProj && filterProj !== "__all") base = base.filter(t => t.project === filterProj);
    if (stage === "live") return base.filter(t => ["dispatched","working","blocked"].includes(t.stage));
    if (stage === "done") return base.filter(t => t.stage === "done");
    return base;
  }, [stage, filterProj, allTasks]);

  // Group tasks by project — alphabetical, "Unassigned" last for
  // null/empty project rows. Mirrors lib/dashboard.js#groupTasksByProject
  // and the Intake / Sessions Health grouping convention so all three
  // tabs render consistently. Items within a group keep API (created_at
  // DESC) order — no stage-rank reshuffle on the 5s polling tick.
  const grouped = useMemoX(() => {
    const m = new Map();
    for (const t of list) {
      const raw = t.project;
      const key = (typeof raw === 'string' && raw.trim() !== '') ? raw : "Unassigned";
      if (!m.has(key)) m.set(key, []);
      m.get(key).push(t);
    }
    const named = [];
    let unassigned = null;
    for (const [project, items] of m) {
      if (project === "Unassigned") unassigned = [project, items];
      else named.push([project, items]);
    }
    named.sort((a, b) => (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0));
    if (unassigned) named.push(unassigned);
    return named;
  }, [list]);

  const [collapsedGroups, setCollapsedGroups] = useStateX(() => {
    try { return JSON.parse(localStorage.getItem("lh.tasks.collapsed") || "{}"); }
    catch { return {}; }
  });
  useEffectX(() => {
    try { localStorage.setItem("lh.tasks.collapsed", JSON.stringify(collapsedGroups)); } catch {}
  }, [collapsedGroups]);
  const toggleGroup = (proj) => setCollapsedGroups(p => ({ ...p, [proj]: !p[proj] }));

  const counts = {
    live: allTasks.filter(t=>["dispatched","working","blocked"].includes(t.stage)).length,
    done: allTasks.filter(t=>t.stage==="done").length,
    all:  allTasks.length,
  };

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <div className="page-title">Tasks</div>
          <div className="page-sub">lifecycle - {counts.live} live - {counts.done} done</div>
        </div>
        <div className="page-actions">
          <div className="seg">
            <button className={"seg-btn"+(stage==="live"?" on":"")} onClick={()=>setStage("live")}>Live <span className="cnt">{counts.live}</span></button>
            <button className={"seg-btn"+(stage==="done"?" on":"")} onClick={()=>setStage("done")}>Done <span className="cnt">{counts.done}</span></button>
            <button className={"seg-btn"+(stage==="all"?" on":"")}  onClick={()=>setStage("all")}>All <span className="cnt">{counts.all}</span></button>
          </div>
          {setFilterProj && <window.ProjectFilter value={filterProj} onChange={setFilterProj} tasks={allTasks}/>}
          <button className="btn btn-ghost"><I.Plus/> New task</button>
        </div>
      </div>

      {grouped.length === 0 && <div className="empty" style={{padding:60}}>no tasks</div>}
      <div className="sessions-grid">
        {grouped.map(([proj, items]) => {
          const collapsed = !!collapsedGroups[proj];
          const projMeta = PROJECTS_X.find(p => p.id === proj);
          return (
            <div className={"proj-group" + (collapsed ? " collapsed" : "")} key={proj}>
              <div className="proj-group-head" onClick={() => toggleGroup(proj)}>
                <button
                  className="proj-group-chevron"
                  aria-label={collapsed ? "Expand" : "Collapse"}
                  onClick={(e) => { e.stopPropagation(); toggleGroup(proj); }}
                >
                  <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                    <path d="M3 2L7 5L3 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
                  </svg>
                </button>
                <span className="proj-group-name">{proj}</span>
                <span className="proj-group-count">{items.length}{projMeta ? " - " + projMeta.short : ""}</span>
              </div>
              {!collapsed && (
                <div className="task-table">
                  <div className="task-row task-row-head">
                    <span>ID</span>
                    <span>Title</span>
                    <span>Stage</span>
                    <span>Updated</span>
                  </div>
                  {items.map(t => (
                    <div key={t.id} className={"task-row" + (selectedId===t.id?" active":"")} onClick={() => onSelect(t)}>
                      <span className="id">{t.id}</span>
                      <div>
                        <div className="t-title">{t.title}</div>
                        {t.depends_on && <div className="t-dep">&darr; depends on <span style={{color:"var(--text-2)"}}>{t.depends_on}</span></div>}
                      </div>
                      <StageTagX s={t.stage}/>
                      <span className="ago">{timeAgoX(t.updated_at)}</span>
                    </div>
                  ))}
                </div>
              )}
            </div>
          );
        })}
      </div>
    </div>
  );
}

// =============== Queue (dedicated) ===============
function QueueView({ onSelect, selectedId, filterProj, setFilterProj, queue, sessions, refreshQueue }) {
  const [showOnly, setShowOnly] = useStateX("active"); // active | pending | all
  const [menuOpen, setMenuOpen] = useStateX(null);
  const [toast, setToast] = useStateX(null);
  const [collapsedSessions, setCollapsedSessions] = useStateX(() => {
    try { return JSON.parse(localStorage.getItem("lh.queue.collapsed") || "{}"); }
    catch { return {}; }
  });
  useEffectX(() => {
    try { localStorage.setItem("lh.queue.collapsed", JSON.stringify(collapsedSessions)); } catch {}
  }, [collapsedSessions]);
  const toggleCollapse = (k) => setCollapsedSessions(p => ({ ...p, [k]: !p[k] }));

  const sessionsList = sessions || [];
  const allQueue = queue || [];
  const sessionsById = Object.fromEntries(sessionsList.map(s => [s.id, s]));

  const filtered = useMemoX(() => {
    let base = allQueue;
    if (filterProj && filterProj !== "__all") {
      base = base.filter(q => {
        const s = sessionsById[q.session_id];
        return s && s.project === filterProj;
      });
    }
    if (showOnly === "pending") return base.filter(q => q.status === "pending");
    if (showOnly === "active") return base.filter(q => q.status === "pending" || q.status === "sent" || q.status === "claimed");
    return base;
  }, [showOnly, filterProj, allQueue, sessionsById]);

  const grouped = useMemoX(() => {
    const m = new Map();
    for (const q of filtered) {
      const key = q.session_id;
      if (!m.has(key)) m.set(key, []);
      m.get(key).push(q);
    }
    return [...m.entries()].map(([sid, items]) => ({ session: sessionsById[sid], items }));
  }, [filtered, sessionsById]);

  const counts = {
    active: allQueue.filter(q=>q.status==="pending"||q.status==="sent").length,
    pending: allQueue.filter(q=>q.status==="pending").length,
    all: allQueue.length,
  };

  const showToast = (msg, kind = "info") => {
    setToast({ msg, kind });
    setTimeout(() => setToast(null), 2200);
  };

  const cancelQueueItem = async (q, e) => {
    e.stopPropagation();
    setMenuOpen(null);
    try {
      await patchQueueItemX(q.id, { status: "cancelled" });
      showToast(`Cancelled ${q.id}`, "warn");
      if (refreshQueue) refreshQueue();
    } catch (err) {
      showToast(`Failed to cancel: ${err.message}`, "err");
    }
  };

  const requeueItem = async (q, e) => {
    e.stopPropagation();
    setMenuOpen(null);
    try {
      await patchQueueItemX(q.id, { status: "pending" });
      showToast(`Re-queued ${q.id}`, "info");
      if (refreshQueue) refreshQueue();
    } catch (err) {
      showToast(`Failed to re-queue: ${err.message}`, "err");
    }
  };

  const deleteItem = async (q, e) => {
    e.stopPropagation();
    setMenuOpen(null);
    try {
      await deleteQueueItemX(q.id);
      showToast(`Deleted ${q.id}`, "warn");
      if (refreshQueue) refreshQueue();
    } catch (err) {
      showToast(`Failed to delete: ${err.message}`, "err");
    }
  };

  const copyId = (q, e) => {
    e.stopPropagation();
    setMenuOpen(null);
    if (navigator.clipboard) navigator.clipboard.writeText(q.id).catch(()=>{});
    showToast(`Copied ${q.id}`, "info");
  };

  const toggleMenu = (id, e) => {
    e.stopPropagation();
    setMenuOpen(prev => prev === id ? null : id);
  };

  React.useEffect(() => {
    if (!menuOpen) return;
    const onDoc = (e) => {
      if (!e.target.closest(".q-actions, .q-action-menu")) setMenuOpen(null);
    };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [menuOpen]);

  return (
    <div className="page">
      <div className="page-head">
        <div>
          <div className="page-title">Queue</div>
          <div className="page-sub">FIFO per session - {counts.pending} pending - {counts.active} active</div>
        </div>
        <div className="page-actions">
          <div className="seg">
            <button className={"seg-btn"+(showOnly==="active"?" on":"")}  onClick={()=>setShowOnly("active")}>Active <span className="cnt">{counts.active}</span></button>
            <button className={"seg-btn"+(showOnly==="pending"?" on":"")} onClick={()=>setShowOnly("pending")}>Pending <span className="cnt">{counts.pending}</span></button>
            <button className={"seg-btn"+(showOnly==="all"?" on":"")}     onClick={()=>setShowOnly("all")}>All <span className="cnt">{counts.all}</span></button>
          </div>
          {setFilterProj && <window.ProjectFilter value={filterProj} onChange={setFilterProj} queue={allQueue} sessions={sessionsList}/>}
        </div>
      </div>

      {grouped.length === 0 && <div className="empty" style={{padding:60}}>queue empty</div>}
      <div className="sessions-grid">
        {grouped.map(({ session, items }) => {
          const key = session?.id || "orphan";
          const collapsed = !!collapsedSessions[key];
          return (
          <div className={"proj-group" + (collapsed ? " collapsed" : "")} key={key}>
            <div className="proj-group-head" onClick={() => toggleCollapse(key)}>
              <button
                className="proj-group-chevron"
                aria-label={collapsed ? "Expand" : "Collapse"}
                onClick={(e) => { e.stopPropagation(); toggleCollapse(key); }}
              >
                <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
                  <path d="M3 2L7 5L3 8" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round" strokeLinejoin="round"/>
                </svg>
              </button>
              <span className={"health-dot " + (session?.health || "idle")}></span>
              <span className="proj-group-name">{session?.tmux_name || "(orphaned)"}</span>
              <span className="proj-group-count">{items.length} items - {session?.project ? (session.project).replace(/^\d+_/, "") : "--"}</span>
              <div className="proj-group-actions" onClick={(e) => e.stopPropagation()}>
                <button className="btn btn-ghost"><I.Plus/> Enqueue</button>
              </div>
            </div>
            {!collapsed && (
            <div className="q-table">
              <div className="q-row q-row-head">
                <span>#</span>
                <span>ID</span>
                <span>Status</span>
                <span>Text</span>
                <span>Created</span>
                <span>Sent</span>
                <span></span>
              </div>
              {items.map(q => {
                return (
                <div
                  key={q.id}
                  className={"q-row" + (selectedId===q.id?" active":"")}
                  onClick={() => onSelect(q)}
                >
                  <span className="pos">{q.position}</span>
                  <span className="id">{q.id}</span>
                  <span><StageTagX s={q.status}/></span>
                  <span className="q-text">{q.text}</span>
                  <span className="ago">{timeAgoX(q.created_at)}</span>
                  <span className="ago">{q.sent_at ? timeAgoX(q.sent_at) : "--"}</span>
                  <span className="q-actions">
                    {q.status === "pending" && (
                      <button
                        className="icon-btn"
                        title="Cancel queue item"
                        onClick={(e) => cancelQueueItem(q, e)}
                      ><I.X/></button>
                    )}
                    {q.status === "cancelled" && (
                      <button
                        className="icon-btn"
                        title="Re-queue"
                        onClick={(e) => requeueItem(q, e)}
                      ><I.Arrow/></button>
                    )}
                    <button
                      className={"icon-btn" + (menuOpen === q.id ? " on" : "")}
                      onClick={(e) => toggleMenu(q.id, e)}
                      title="More"
                    ><I.More/></button>
                    {menuOpen === q.id && (
                      <div className="q-action-menu" onClick={(e) => e.stopPropagation()}>
                        <button onClick={(e) => copyId(q, e)}>Copy ID</button>
                        <button onClick={(e) => { e.stopPropagation(); setMenuOpen(null); onSelect(q); }}>View details</button>
                      </div>
                    )}
                  </span>
                </div>
                );
              })}
            </div>
            )}
          </div>
          );
        })}
      </div>
    </div>
  );
}

window.LHViewsExtra = { IntakeView, TasksView, QueueView, ProjectPick };
