// SOLARA SDR — operator console shell.
// Pulls all data from real /api/* endpoints. Polls /api/status every 8s for
// live KPI updates without blowing up the connection count.

function useApi(url, initial = null, deps = []) {
  const [data, setData] = useState(initial);
  const [error, setError] = useState(null);
  const reload = useCallback(() => {
    fetch(url)
      .then((r) => (r.ok ? r.json() : Promise.reject(new Error("HTTP " + r.status))))
      .then(setData)
      .catch(setError);
  }, [url]);
  useEffect(() => { reload(); }, deps); // eslint-disable-line
  return { data, error, reload };
}

window.useCallback = React.useCallback;

function App() {
  const [view, setView] = useState("overview");
  const [threadId, setThreadId] = useState(null);
  const [focusedCamp, setFocusedCamp] = useState(null);
  const [cmdkOpen, setCmdkOpen] = useState(false);
  const [railOpen, setRailOpen] = useState(false);
  const [asideOpen, setAsideOpen] = useState(false);
  const [now, setNow] = useState(new Date());

  // Live data sources.
  const [status, setStatus] = useState(null);
  const [threads, setThreads] = useState([]);
  const [funnel, setFunnel] = useState([]);
  const [sparkline, setSparkline] = useState({ hours: 12, buckets: [] });
  const [escalationsQueue, setEscalationsQueue] = useState([]);

  const refreshAll = useCallback(() => {
    fetch("/api/status").then((r) => r.json()).then(setStatus);
    fetch("/api/threads?limit=60").then((r) => r.json()).then((d) => setThreads(d.threads || []));
    fetch("/api/funnel").then((r) => r.json()).then((d) => setFunnel(d.rows || []));
    fetch("/api/sparkline/sends?hours=12").then((r) => r.json()).then(setSparkline);
    fetch("/api/escalations/queue").then((r) => r.json()).then((d) => setEscalationsQueue(d.escalations || []));
  }, []);

  // Initial load + poll.
  useEffect(() => {
    refreshAll();
    const t = setInterval(refreshAll, 8000);
    return () => clearInterval(t);
  }, [refreshAll]);

  // Cmd+K + Escape.
  useEffect(() => {
    const onKey = (e) => {
      if ((e.metaKey || e.ctrlKey) && e.key.toLowerCase() === "k") {
        e.preventDefault();
        setCmdkOpen((o) => !o);
      }
      if (e.key === "Escape") {
        setCmdkOpen(false);
        setRailOpen(false);
        setAsideOpen(false);
      }
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  // Body class lock when any drawer is open (mobile).
  useEffect(() => {
    document.body.classList.toggle("drawer-open", railOpen || asideOpen);
  }, [railOpen, asideOpen]);

  // Clock for the footer.
  useEffect(() => {
    const t = setInterval(() => setNow(new Date()), 1000);
    return () => clearInterval(t);
  }, []);

  const nav = (v, id) => {
    setView(v);
    if (v === "inbox" && id) setThreadId(id);
    if (v === "campaigns" && id) setFocusedCamp(id);
    setRailOpen(false);
  };

  // Loading shell — show as soon as status is in.
  if (!status) {
    return (
      <div className="app">
        <header className="header">
          <div className="brand">
            <div className="brand-mark">777</div>
            <span>SOLARA</span>
            <span className="brand-sep">/</span>
            <span className="brand-product">SDR Agent</span>
          </div>
        </header>
        <main className="main">
          <div style={{ padding: 40, color: "var(--fg-muted)" }}>Loading…</div>
        </main>
        <footer className="footer">
          <span><span className="pulse" />connecting</span>
        </footer>
      </div>
    );
  }

  // Compose the data prop each view sees (single source of truth for child).
  const data = {
    ...status,
    threads,
    funnel,
    sparkline,
    escalations_queue: escalationsQueue,
    engine_status: "scaffold", // Day-2 sender lights this up to "operational"
  };

  const inflightCount =
    (status.totals?.leads_inflight || 0);

  const timeStr = now.toLocaleTimeString("en-US", {
    hour: "2-digit",
    minute: "2-digit",
    second: "2-digit",
    hour12: false,
  });

  return (
    <div className="app">
      {/* ============ HEADER ============ */}
      <header className="header">
        <button
          className="iconbtn rail-toggle"
          onClick={() => setRailOpen((o) => !o)}
          title="Menu"
        >
          <Icon name="menu" size={14} />
        </button>
        <div className="brand">
          <div className="brand-mark">777</div>
          <span>SOLARA</span>
          <span className="brand-sep">/</span>
          <span className="brand-product">SDR Agent</span>
        </div>
        <span className="env-pill">
          <span className="env-dot" />
          production · contabo
        </span>

        <div className="header-grow" />

        <div className="cmdk" onClick={() => setCmdkOpen(true)}>
          <Icon name="search" size={13} />
          <span>Jump to lead, campaign, thread…</span>
          <span className="kbd">⌘K</span>
        </div>
        <button
          className="iconbtn aside-toggle"
          onClick={() => setAsideOpen((o) => !o)}
          title="Activity"
        >
          <Icon name="bolt" size={14} />
          {escalationsQueue.length > 0 && (
            <span className="badge">{escalationsQueue.length}</span>
          )}
        </button>
        <button className="iconbtn" title="Notifications">
          <Icon name="bell" size={14} />
          {status.open_escalations > 0 && (
            <span className="badge">{status.open_escalations}</span>
          )}
        </button>
        <div className="avatar">DG</div>
      </header>

      {/* Drawer backdrop on mobile */}
      {(railOpen || asideOpen) && (
        <div
          className="drawer-backdrop"
          onClick={() => {
            setRailOpen(false);
            setAsideOpen(false);
          }}
        />
      )}

      {/* ============ RAIL ============ */}
      <nav className={`rail ${railOpen ? "open" : ""}`}>
        <div className="rail-section" style={{ paddingTop: 0 }}>Workspace</div>
        {[
          { v: "overview", ic: "home", label: "Overview" },
          { v: "inbox", ic: "inbox", label: "Inbox", count: threads.filter((t) => t.unread).length },
          { v: "pipeline", ic: "pipeline", label: "Pipeline", count: status.totals?.leads_inflight || 0 },
          { v: "campaigns", ic: "campaign", label: "Campaigns", count: status.campaigns.length },
        ].map((n) => (
          <div
            key={n.v}
            className={`nav-item ${view === n.v ? "active" : ""}`}
            onClick={() => nav(n.v)}
          >
            <Icon name={n.ic} className="icon" /> {n.label}
            {n.count != null && <span className="count">{n.count}</span>}
          </div>
        ))}

        <div className="rail-section">Campaigns</div>
        {status.campaigns.map((c) => {
          const pc = status.per_campaign?.[c.id] || {};
          const replyRate =
            pc.leads_total > 0
              ? ((pc.leads_replied || 0) / pc.leads_total) * 100
              : 0;
          return (
            <div
              key={c.id}
              className="campaign-item"
              onClick={() => nav("campaigns", c.id)}
            >
              <span className="swatch" style={{ background: c.color }} />
              <span className="name">{c.display_name}</span>
              <span className="meta">{replyRate.toFixed(1)}%</span>
            </div>
          );
        })}

        <div className="rail-section">Status</div>
        <div
          style={{
            padding: "4px 10px",
            fontSize: 11.5,
            color: "var(--fg-muted)",
            lineHeight: 1.55,
          }}
        >
          <div className="row-flex" style={{ justifyContent: "space-between", marginBottom: 3 }}>
            <span>Campaigns</span>
            <span className="mono" style={{ color: "hsl(158 70% 30%)" }}>
              {status.campaigns.filter((c) => c.enabled).length} / {status.campaigns.length} ●
            </span>
          </div>
          <div className="row-flex" style={{ justifyContent: "space-between", marginBottom: 3 }}>
            <span>LLM engine</span>
            <span className="mono" style={{ color: "hsl(38 70% 35%)" }}>
              pending
            </span>
          </div>
          <div className="row-flex" style={{ justifyContent: "space-between" }}>
            <span>Suppressions</span>
            <span className="mono">{status.totals?.suppressions || 0}</span>
          </div>
        </div>

        <div style={{ flex: 1 }} />

        <div
          style={{
            padding: "10px 12px",
            margin: "6px 0 0",
            borderRadius: 10,
            background:
              "linear-gradient(135deg, hsl(var(--hsl-primary) / 0.08), hsl(var(--hsl-primary) / 0.02))",
            border: "1px solid hsl(var(--hsl-primary) / 0.2)",
            fontSize: 11.5,
          }}
        >
          <div
            style={{
              display: "flex",
              alignItems: "center",
              gap: 6,
              color: "var(--primary)",
              fontWeight: 600,
              marginBottom: 4,
            }}
          >
            <Icon name="bolt" size={12} /> Day-2 roadmap
          </div>
          <div style={{ color: "var(--fg)", lineHeight: 1.5 }}>
            LLM draft engine + IMAP listener + scheduler. Data plane is live,
            send plane is wired but inert.
          </div>
        </div>
      </nav>

      {/* ============ MAIN ============ */}
      <main className="main">
        {view === "overview" && (
          <OverviewView
            data={data}
            onNav={nav}
            onOpenAside={() => setAsideOpen(true)}
          />
        )}
        {view === "inbox" && (
          <InboxView
            data={data}
            threadId={threadId}
            setThreadId={setThreadId}
          />
        )}
        {view === "pipeline" && <PipelineView data={data} onNav={nav} />}
        {view === "campaigns" && (
          <CampaignsView data={data} onUpload={refreshAll} />
        )}
      </main>

      {/* ============ ASIDE ============ */}
      <aside className={`aside ${asideOpen ? "open" : ""}`}>
        <div className="aside-head">
          <span className="aside-title">Recent activity</span>
          <span className="live"><span className="dot" />LIVE</span>
        </div>
        <div style={{ flex: 1, overflowY: "auto" }}>
          {(status.recent || []).map((e, i) => {
            const kind = (e.action || "").includes("imported")
              ? "draft"
              : (e.action || "").includes("send")
              ? "send"
              : (e.action || "").includes("escalat")
              ? "escalate"
              : "draft";
            return (
              <div className={`act ${kind}`} key={i}>
                <div className="icon">
                  <Icon
                    name={
                      kind === "send"
                        ? "send"
                        : kind === "escalate"
                        ? "flag"
                        : "pen"
                    }
                    size={11}
                  />
                </div>
                <div>
                  <div><span className="who">{e.actor || "system"}</span></div>
                  <div className="desc">{e.action}</div>
                  {e.target && (
                    <div className="mono" style={{ fontSize: 10.5, color: "var(--fg-muted)", marginTop: 2 }}>
                      {e.target}
                    </div>
                  )}
                  <div className="when">{fmt.rel(e.ts)}</div>
                </div>
              </div>
            );
          })}
          {(!status.recent || status.recent.length === 0) && (
            <EmptyState
              icon="log"
              title="No recent activity"
              text="Imports, sends, and escalations stream here as they happen."
            />
          )}
        </div>
      </aside>

      {/* ============ FOOTER ============ */}
      <footer className="footer">
        <span><span className="pulse" />SDR engine</span>
        <span className="sep">|</span>
        <span>v0.2-buddy</span>
        <span className="sep">|</span>
        <span>{fmt.num(inflightCount)} in flight</span>
        <span className="sep">|</span>
        <span>{fmt.num(status.totals?.suppressions || 0)} suppressed</span>
        <div className="footer-grow" />
        <span>{timeStr}</span>
      </footer>

      {/* ============ COMMAND PALETTE ============ */}
      {cmdkOpen && (
        <div className="cmdk-modal" onClick={() => setCmdkOpen(false)}>
          <div className="cmdk-card" onClick={(e) => e.stopPropagation()}>
            <div className="cmdk-input">
              <Icon name="search" size={16} className="muted" />
              <input
                autoFocus
                placeholder="Jump to lead, campaign, view…"
              />
              <span
                className="kbd"
                style={{
                  padding: "2px 5px",
                  border: "1px solid var(--border)",
                  borderRadius: 4,
                  fontFamily: "var(--font-mono)",
                  fontSize: 10.5,
                  color: "var(--fg-muted)",
                }}
              >
                esc
              </span>
            </div>
            <div className="cmdk-results">
              <div className="cmdk-section">Navigate</div>
              {[
                ["overview", "home", "Go to Overview", "G O"],
                ["inbox", "inbox", "Open Inbox", "G I"],
                ["pipeline", "pipeline", "View Pipeline", "G P"],
                ["campaigns", "campaign", "Manage Campaigns", "G C"],
              ].map(([v, ic, label, kb]) => (
                <div
                  className="cmdk-item"
                  key={v}
                  onClick={() => {
                    nav(v);
                    setCmdkOpen(false);
                  }}
                >
                  <Icon name={ic} size={14} className="muted" />
                  <span>{label}</span>
                  <span className="k">{kb}</span>
                </div>
              ))}
              <div className="cmdk-section">Campaigns</div>
              {status.campaigns.map((c) => (
                <div
                  className="cmdk-item"
                  key={c.id}
                  onClick={() => {
                    nav("campaigns", c.id);
                    setCmdkOpen(false);
                  }}
                >
                  <span
                    style={{
                      width: 8,
                      height: 8,
                      borderRadius: 2,
                      background: c.color,
                    }}
                  />
                  <span>{c.display_name}</span>
                  <span className="muted" style={{ fontSize: 11, marginLeft: 6 }}>
                    {c.persona_name}
                  </span>
                </div>
              ))}
              {threads.length > 0 && (
                <>
                  <div className="cmdk-section">Recent threads</div>
                  {threads.slice(0, 5).map((t) => (
                    <div
                      className="cmdk-item"
                      key={t.id}
                      onClick={() => {
                        nav("inbox", t.id);
                        setCmdkOpen(false);
                      }}
                    >
                      <Icon name="mail" size={14} className="muted" />
                      <span>{t.lead.name}</span>
                      <span
                        className="muted"
                        style={{ fontSize: 11, marginLeft: 6 }}
                      >
                        {t.lead.company || t.lead.email}
                      </span>
                    </div>
                  ))}
                </>
              )}
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
