/* global React, Ic, fluxActions, timeAgo, toast, Modal, DangerButton */
const { useState: useCS, useEffect: useCE, useRef: useCR } = React;

const REFRESH_MS = 5000;

function StatePill({ state }) {
  const s = (state || "").toLowerCase();
  if (s === "running") return <span className="pill green dot">RUNNING</span>;
  if (s === "restarting" || s === "created" || s === "paused")
    return <span className="pill yellow dot">{s.toUpperCase()}</span>;
  if (s === "exited" || s === "dead")
    return <span className="pill red dot">{s.toUpperCase()}</span>;
  return <span className="pill">{(state || "unknown").toUpperCase()}</span>;
}

function LogsModal({ c, onClose }) {
  const [st, setSt] = useCS({ loading: true, logs: "", error: "" });
  const preRef = useCR(null);

  const load = async () => {
    setSt((s) => ({ ...s, loading: true }));
    const r = await fluxActions.getContainerLogs(c.id);
    setSt({ loading: false, logs: r.logs || "", error: r.ok ? "" : (r.message || "failed") });
  };
  useCE(() => { load(); }, []);
  // keep the view pinned to the newest lines
  useCE(() => { if (preRef.current) preRef.current.scrollTop = preRef.current.scrollHeight; }, [st.logs]);

  return (
    <Modal title={`Logs · ${c.service || c.name}`} icon={Ic.cmd} onClose={onClose} size="lg"
      footer={<>
        <span className="muted mono-sm">last 200 lines</span>
        <span style={{ flex: 1 }} />
        <button className="btn" onClick={load}><Ic.history className="ico" />Refresh</button>
        <button className="btn primary" onClick={onClose}>Close</button>
      </>}>
      {st.loading ? (
        <div style={{ padding: 24, color: "var(--text-3)", fontSize: 13 }}>Loading logs…</div>
      ) : st.error ? (
        <div style={{ padding: 24, color: "var(--text-3)", fontSize: 13 }}>Couldn't load logs — {st.error}</div>
      ) : (
        <pre ref={preRef} className="code" style={{ maxHeight: "58vh", overflow: "auto", whiteSpace: "pre-wrap", wordBreak: "break-word", fontSize: 12, margin: 0 }}>
          {st.logs || "No output yet."}
        </pre>
      )}
    </Modal>
  );
}

function ContainerRow({ c, onLogs, onAction }) {
  const running = c.state === "running";
  const meta = [c.image, ...(c.ports && c.ports.length ? [c.ports.join(", ")] : [])].filter(Boolean).join(" · ");
  return (
    <div className="card" style={{ padding: 16, display: "flex", alignItems: "center", gap: 14 }}>
      <div style={{ width: 38, height: 38, borderRadius: 9, background: "var(--elev-2)", display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0 }}>
        <Ic.box style={{ width: 19, height: 19, color: running ? "#2ee07a" : "var(--text-3)" }} />
      </div>
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <span style={{ fontSize: 14, fontWeight: 600, color: "var(--text)" }}>{c.service || c.name}</span>
          <StatePill state={c.state} />
          {c.scraper && <span className="pill teal">{c.scraper}</span>}
        </div>
        <div className="mono-sm muted" style={{ marginTop: 4, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", maxWidth: 420 }}>{meta}</div>
      </div>
      <div style={{ textAlign: "right", flexShrink: 0, minWidth: 120 }}>
        <div style={{ fontSize: 12.5, color: "var(--text-2)", whiteSpace: "nowrap" }}>{c.status || "—"}</div>
        {c.created && <div style={{ fontSize: 11, color: "var(--text-3)", marginTop: 3 }}>created {timeAgo(c.created)}</div>}
      </div>
      <div style={{ display: "flex", gap: 6, flexShrink: 0 }}>
        <button className="btn ghost sm" onClick={() => onLogs(c)} title="View logs"><Ic.cmd className="ico" />Logs</button>
        {running ? (
          <>
            <button className="btn ghost sm" onClick={() => onAction(c, "restart")} title="Restart"><Ic.history className="ico" />Restart</button>
            <DangerButton className="btn danger sm" confirmLabel="Stop?" onConfirm={() => onAction(c, "stop")}><Ic.x className="ico" />Stop</DangerButton>
          </>
        ) : (
          <button className="btn sm" onClick={() => onAction(c, "start")} title="Start"><Ic.zap className="ico" />Start</button>
        )}
      </div>
    </div>
  );
}

function Containers() {
  const [data, setData] = useCS({ loading: true, connected: false, containers: [], reason: "" });
  const [logsFor, setLogsFor] = useCS(null);
  const [busy, setBusy] = useCS(false);
  const timer = useCR(null);

  const load = async () => {
    const r = await fluxActions.getContainers();
    setData({ loading: false, connected: !!r.connected, containers: r.containers || [], reason: r.reason || "" });
  };

  useCE(() => {
    load();
    timer.current = setInterval(load, REFRESH_MS);
    return () => clearInterval(timer.current);
  }, []);

  const act = async (c, action) => {
    if (busy) return;
    setBusy(true);
    const r = await fluxActions.containerAction(c.id, action);
    setBusy(false);
    if (r.ok) {
      toast(`${action.charAt(0).toUpperCase() + action.slice(1)} sent to ${c.service || c.name}`, "success");
      setTimeout(load, 700); // give Docker a moment, then reflect new state
    }
  };

  const containers = data.containers;
  const running = containers.filter((c) => c.state === "running").length;

  return (
    <div className="view-pad fade-in" style={{ maxWidth: 1100 }}>
      <div className="sec-head">
        <h2>Containers</h2>
        <span className="desc">Live status &amp; control of your scraper containers · auto-refreshes every {REFRESH_MS / 1000}s</span>
        <span className="spacer" />
        <button className="btn" onClick={load}><Ic.history className="ico" />Refresh</button>
      </div>

      <div style={{ display: "grid", gridTemplateColumns: "repeat(3, 1fr)", gap: 12, marginBottom: 18 }}>
        <div className="kpi"><div className="label">Scraper containers</div><div className="value">{containers.length}</div><div className="delta">discovered via Docker</div></div>
        <div className="kpi"><div className="label">Running</div><div className="value green">{running}</div><div className="delta">up right now</div></div>
        <div className="kpi"><div className="label">Stopped</div><div className={`value ${containers.length - running ? "yellow" : ""}`}>{containers.length - running}</div><div className="delta">exited / not running</div></div>
      </div>

      {data.loading ? (
        <div className="empty"><Ic.box className="ic" /><div className="t">Loading…</div></div>
      ) : !data.connected ? (
        <div className="empty">
          <Ic.box className="ic" />
          <div className="t">Docker not connected</div>
          <div className="d">
            The server couldn't reach the Docker daemon{data.reason ? ` — ${data.reason}` : ""}.<br />
            Locally, make sure Docker Desktop is running. When deployed, mount the Docker socket into the app container (see <span className="mono-sm">docker-compose.yml</span>).
          </div>
        </div>
      ) : containers.length === 0 ? (
        <div className="empty">
          <Ic.box className="ic" />
          <div className="t">No scraper containers</div>
          <div className="d">Start them with <span className="mono-sm">docker compose --profile scrapers up -d</span>.</div>
        </div>
      ) : (
        <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
          {containers.map((c) => <ContainerRow key={c.id} c={c} onLogs={setLogsFor} onAction={act} />)}
        </div>
      )}

      {logsFor && <LogsModal c={logsFor} onClose={() => setLogsFor(null)} />}
    </div>
  );
}

Object.assign(window, { Containers });
