/**
 * Read-only web workspace — ticket #13, lot F2 (first shippable increment).
 *
 * The minimal post-pairing surface: list the projects, open one **read-only**,
 * and show a snapshot of its live/work state. No PTY (xterm over WS = F3), no
 * mutation — every call goes through the existing transport-neutral gateways
 * (`project`, `workState`) via DI, so no component touches `@tauri-apps/api`.
 *
 * It reuses the frozen read-model types (`ProjectWorkState`) and only calls the
 * commands B4 puts on the read-only allowlist: `list_projects`, `open_project`,
 * `get_project_work_state`. A deliberately small surface — the full IDE (layout,
 * agents, terminals) is out of scope until the streaming lots.
 */

import { useCallback, useEffect, useState } from "react";

import type { GatewayError, Project, ProjectWorkState } from "@/domain";
import { useGateways } from "@/app/di";
import { Button, Panel, Spinner } from "@/shared";
import { WebAgentCell } from "./WebAgentCell";

function describe(e: unknown): string {
  if (e && typeof e === "object" && "message" in e) {
    return String((e as GatewayError).message);
  }
  return String(e);
}

export function WebWorkspace() {
  const { project, workState } = useGateways();
  const [projects, setProjects] = useState<Project[] | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [openId, setOpenId] = useState<string | null>(null);
  const [snapshot, setSnapshot] = useState<ProjectWorkState | null>(null);
  const [loadingSnapshot, setLoadingSnapshot] = useState(false);
  // The agent currently opened in a live cell (CLI streamed over the WS), if any.
  const [openAgentId, setOpenAgentId] = useState<string | null>(null);

  const openRoot = projects?.find((p) => p.id === openId)?.root ?? null;

  const refresh = useCallback(async () => {
    setError(null);
    try {
      setProjects(await project.listProjects());
    } catch (e) {
      setError(describe(e));
    }
  }, [project]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  const openReadOnly = useCallback(
    async (projectId: string) => {
      setError(null);
      setLoadingSnapshot(true);
      setOpenId(projectId);
      setSnapshot(null);
      setOpenAgentId(null);
      try {
        // Read-only: open resolves the project server-side, then we read the
        // live/work-state snapshot. No layout/agents/PTY are mounted.
        await project.openProject(projectId);
        setSnapshot(await workState.getProjectWorkState(projectId));
      } catch (e) {
        setError(describe(e));
      } finally {
        setLoadingSnapshot(false);
      }
    },
    [project, workState],
  );

  return (
    <div className="flex h-full flex-col gap-4 overflow-y-auto p-6">
      <div className="flex items-center justify-between">
        <h2 className="text-base font-semibold tracking-tight">Projets</h2>
        <Button variant="ghost" size="sm" onClick={() => void refresh()}>
          Rafraîchir
        </Button>
      </div>

      {error && (
        <Panel className="border-danger/40">
          <p className="text-sm text-danger">{error}</p>
        </Panel>
      )}

      {projects === null ? (
        <span className="inline-flex items-center gap-1.5 text-sm text-muted">
          <Spinner size={12} /> Chargement des projets…
        </span>
      ) : projects.length === 0 ? (
        <p className="text-sm text-muted">Aucun projet.</p>
      ) : (
        <ul className="flex flex-col gap-2" data-testid="web-project-list">
          {projects.map((p) => (
            <li key={p.id}>
              <button
                type="button"
                onClick={() => void openReadOnly(p.id)}
                aria-pressed={openId === p.id}
                className="flex w-full flex-col items-start rounded-md border border-border bg-raised px-3 py-2 text-left transition-colors hover:border-primary aria-pressed:border-primary"
              >
                <span className="text-sm font-medium text-content">{p.name}</span>
                <span className="text-xs text-faint">{p.root}</span>
              </button>
            </li>
          ))}
        </ul>
      )}

      {openId && (
        <Panel className="mt-2">
          <div className="mb-2 flex items-center justify-between">
            <h3 className="text-sm font-semibold">
              État (lecture seule)
              <span className="ml-2 rounded bg-canvas px-1.5 py-0.5 text-[0.6rem] uppercase text-muted">
                read-only
              </span>
            </h3>
            {loadingSnapshot && <Spinner size={12} />}
          </div>
          {snapshot ? (
            <WorkStateSnapshot
              snapshot={snapshot}
              openAgentId={openAgentId}
              onOpenAgent={setOpenAgentId}
            />
          ) : loadingSnapshot ? (
            <p className="text-xs text-muted">Chargement de l'état…</p>
          ) : (
            <p className="text-xs text-muted">Aucun état disponible.</p>
          )}
        </Panel>
      )}

      {openId && openRoot && openAgentId && (
        <Panel className="mt-2">
          <div className="mb-2 flex items-center justify-between">
            <h3 className="text-sm font-semibold">Agent</h3>
            <Button variant="ghost" size="sm" onClick={() => setOpenAgentId(null)}>
              Fermer
            </Button>
          </div>
          {/* Re-mount the cell per agent so a switch relaunches/reattaches cleanly. */}
          <WebAgentCell
            key={openAgentId}
            projectId={openId}
            agentId={openAgentId}
            cwd={openRoot}
          />
        </Panel>
      )}
    </div>
  );
}

/** Pure render of the read-only work-state snapshot + per-agent "open" affordance. */
function WorkStateSnapshot({
  snapshot,
  openAgentId,
  onOpenAgent,
}: {
  snapshot: ProjectWorkState;
  openAgentId: string | null;
  onOpenAgent: (agentId: string) => void;
}) {
  if (snapshot.agents.length === 0) {
    return <p className="text-xs text-muted">Aucun agent actif.</p>;
  }
  return (
    <ul className="flex flex-col gap-1.5" data-testid="web-workstate">
      {snapshot.agents.map((a) => (
        <li key={a.agentId} className="flex items-center justify-between gap-2 text-xs">
          <span className="text-content">{a.name}</span>
          <span className="flex items-center gap-2 text-faint">
            <span>{a.live ? `live · ${a.live.kind}` : "offline"}</span>
            <span
              className={
                a.busy.state === "busy" ? "text-warning" : "text-success"
              }
            >
              {a.busy.state === "busy" ? "busy" : "idle"}
            </span>
            <Button
              variant="ghost"
              size="sm"
              aria-pressed={openAgentId === a.agentId}
              onClick={() => onOpenAgent(a.agentId)}
            >
              Ouvrir
            </Button>
          </span>
        </li>
      ))}
    </ul>
  );
}
