import type { Doc, Id } from "@code/backend/convex/_generated/dataModel";
import { Button } from "@code/ui/components/button";
import { Input } from "@code/ui/components/input";
import { Textarea } from "@code/ui/components/textarea";
import {
  ArrowUpRight,
  Bot,
  CircleAlert,
  ExternalLink,
  FolderGit2,
  GitFork,
  GitPullRequest,
  LoaderCircle,
  Plus,
  Sparkles,
} from "lucide-react";

import UserMenu from "@/components/user-menu";
import { useProjectWorkspace } from "@/hooks/use-project-workspace";
import type {
  ProjectIssueSummary,
  ProjectLoopView,
} from "@/lib/projects/project-evidence";

interface Project {
  readonly id: string;
  readonly name: string;
  readonly sources: readonly {
    readonly defaultBranch?: string;
    readonly host: string;
    readonly repositoryPath: string;
    readonly url: string;
  }[];
}

const formatStatus = (status: Doc<"projectIssues">["status"]): string => {
  if (status === "needs-input") {
    return "Needs input";
  }
  if (status === "working") {
    return "In progress";
  }
  return status.charAt(0).toUpperCase() + status.slice(1);
};

const statusClasses: Record<Doc<"projectIssues">["status"], string> = {
  completed: "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300",
  failed: "bg-destructive/15 text-destructive",
  "needs-input": "bg-orange-500/15 text-orange-700 dark:text-orange-300",
  open: "bg-muted text-muted-foreground",
  queued: "bg-violet-500/15 text-violet-700 dark:text-violet-300",
  working: "bg-blue-500/15 text-blue-700 dark:text-blue-300",
};

const verificationIconClass = (
  verification: ProjectLoopView["verification"]
): string => {
  if (verification === "passed") {
    return "text-emerald-600";
  }
  if (verification === "failed" || verification === "blocked") {
    return "text-orange-600";
  }
  return "text-muted-foreground";
};

const checkStateClass = (
  state: ProjectLoopView["verificationChecks"][number]["state"]
): string => {
  if (state === "complete") {
    return "bg-emerald-500 text-white";
  }
  if (state === "attention") {
    return "bg-orange-500 text-white";
  }
  if (state === "current") {
    return "bg-blue-500 text-white";
  }
  return "bg-muted text-muted-foreground";
};

const LoadingLine = ({ label }: { readonly label: string }) => (
  <div className="flex items-center gap-2 text-xs text-muted-foreground">
    <LoaderCircle className="size-3.5 animate-spin" />
    {label}
  </div>
);

interface RepositoryFormProps {
  readonly busy: boolean;
  readonly onRepositoryChange: (value: string) => void;
  readonly onRepositorySubmit: () => void;
  readonly value: string;
}

const RepositoryForm = ({
  busy,
  onRepositoryChange,
  onRepositorySubmit,
  value,
}: RepositoryFormProps) => (
  <form
    className="space-y-3 border-b border-border/70 p-4"
    onSubmit={(event) => {
      event.preventDefault();
      onRepositorySubmit();
    }}
  >
    <div>
      <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
        Connect project
      </p>
      <p className="mt-1 text-xs leading-5 text-muted-foreground">
        Bring a public repository into the project loop.
      </p>
    </div>
    <Input
      aria-label="Public Git repository URL"
      onChange={(event) => onRepositoryChange(event.target.value)}
      placeholder="https://github.com/owner/repo"
      required
      value={value}
    />
    <Button className="w-full" disabled={busy} type="submit">
      {busy ? (
        <LoaderCircle className="animate-spin" data-icon="inline-start" />
      ) : (
        <GitFork data-icon="inline-start" />
      )}
      {busy ? "Connecting" : "Connect repository"}
    </Button>
  </form>
);

interface ProjectSidebarProps {
  readonly onProjectSelect: (projectId: Id<"projects">) => void;
  readonly projects: readonly Project[] | undefined;
  readonly selectedId: Id<"projects"> | null;
}

const ProjectSidebar = ({
  onProjectSelect,
  projects,
  selectedId,
}: ProjectSidebarProps) => {
  const renderProjects = () => {
    if (projects === undefined) {
      return <LoadingLine label="Loading projects" />;
    }
    if (projects.length === 0) {
      return (
        <p className="text-xs leading-5 text-muted-foreground">
          Connect a repository to create the first project workspace.
        </p>
      );
    }
    return (
      <div className="grid gap-1.5">
        {projects.map((project) => {
          const [source] = project.sources;
          const selected = selectedId === project.id;
          return (
            <button
              className={`w-full border px-3 py-2.5 text-left transition-colors ${
                selected
                  ? "border-foreground/20 bg-foreground text-background"
                  : "border-transparent hover:border-border hover:bg-muted/60"
              }`}
              key={project.id}
              onClick={() => onProjectSelect(project.id as Id<"projects">)}
              type="button"
            >
              <span className="block truncate text-sm font-medium">
                {project.name}
              </span>
              <span
                className={`mt-1 block truncate text-[11px] ${
                  selected ? "text-background/65" : "text-muted-foreground"
                }`}
              >
                {source
                  ? `${source.host}/${source.repositoryPath}`
                  : "No source"}
              </span>
            </button>
          );
        })}
      </div>
    );
  };

  return (
    <aside className="flex min-h-0 flex-col border-b border-border/70 bg-card/35 md:border-r md:border-b-0">
      <div className="flex items-center justify-between border-b border-border/70 px-4 py-3">
        <div>
          <p className="text-sm font-semibold">Projects</p>
          <p className="text-xs text-muted-foreground">
            Your connected workspaces
          </p>
        </div>
        <FolderGit2 className="size-4 text-muted-foreground" />
      </div>
      <nav
        aria-label="Connected projects"
        className="min-h-0 flex-1 overflow-y-auto p-3"
      >
        {renderProjects()}
      </nav>
      <div className="border-t border-border/70 p-3">
        <div className="flex items-start gap-2 border bg-muted/45 p-3">
          <Sparkles className="mt-0.5 size-3.5 shrink-0 text-lime-600 dark:text-lime-300" />
          <p className="text-[11px] leading-4 text-muted-foreground">
            Project context stays attached to every issue and run.
          </p>
        </div>
      </div>
    </aside>
  );
};

interface IssueComposerProps {
  readonly body: string;
  readonly busy: boolean;
  readonly onIssueBodyChange: (value: string) => void;
  readonly onIssueSubmit: () => void;
  readonly onIssueTitleChange: (value: string) => void;
  readonly title: string;
}

const IssueComposer = ({
  body,
  busy,
  onIssueBodyChange,
  onIssueSubmit,
  onIssueTitleChange,
  title,
}: IssueComposerProps) => (
  <form
    className="border border-border/70 bg-card/60 p-4 shadow-[0_14px_32px_-24px_rgb(0_0_0/0.45)] sm:p-5"
    onSubmit={(event) => {
      event.preventDefault();
      onIssueSubmit();
    }}
  >
    <div className="flex items-start justify-between gap-4">
      <div>
        <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
          Create work
        </p>
        <h2 className="mt-1 text-base font-semibold tracking-tight">
          What should Zopu move forward?
        </h2>
      </div>
      <div className="grid size-8 shrink-0 place-items-center bg-lime-400 text-black">
        <Plus className="size-4" />
      </div>
    </div>
    <div className="mt-4 grid gap-2.5">
      <Input
        aria-label="Issue title"
        onChange={(event) => onIssueTitleChange(event.target.value)}
        placeholder="Outcome or issue title"
        required
        value={title}
      />
      <Textarea
        aria-label="Issue description"
        onChange={(event) => onIssueBodyChange(event.target.value)}
        placeholder="Describe the desired result, constraints, or evidence to start from."
        required
        rows={3}
        value={body}
      />
    </div>
    <div className="mt-3 flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
      <p className="text-[11px] leading-4 text-muted-foreground">
        The issue becomes durable project work before an agent run starts.
      </p>
      <Button className="w-full sm:w-auto" disabled={busy} type="submit">
        {busy ? (
          <LoaderCircle className="animate-spin" data-icon="inline-start" />
        ) : (
          <Plus data-icon="inline-start" />
        )}
        {busy ? "Creating" : "Create issue"}
      </Button>
    </div>
  </form>
);

interface IssueCardProps {
  readonly issue: Doc<"projectIssues">;
  readonly selected: boolean;
  readonly onIssueSelect: (issueId: Id<"projectIssues">) => void;
  readonly onIssueStart: (
    issueId: Id<"projectIssues">,
    issueNumber: number,
    title: string
  ) => void;
  readonly pendingAction: string | null;
}

const IssueCard = ({
  issue,
  onIssueSelect,
  onIssueStart,
  pendingAction,
  selected,
}: IssueCardProps) => {
  const canStart = issue.status === "open" || issue.status === "failed";
  const startPending = pendingAction === `issue:${issue._id}`;

  return (
    <article
      className={`border p-4 transition-colors ${
        selected
          ? "border-blue-500/35 bg-blue-500/5"
          : "border-border/70 bg-card/45 hover:border-foreground/20"
      }`}
    >
      <button
        className="w-full text-left"
        onClick={() => onIssueSelect(issue._id)}
        type="button"
      >
        <div className="flex flex-wrap items-center justify-between gap-2">
          <span className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
            Issue #{issue.number}
          </span>
          <span
            className={`rounded-full px-2 py-1 text-[10px] font-semibold ${statusClasses[issue.status]}`}
          >
            {formatStatus(issue.status)}
          </span>
        </div>
        <h3 className="mt-3 text-sm font-semibold leading-5">{issue.title}</h3>
        <p className="mt-1.5 line-clamp-2 text-xs leading-5 text-muted-foreground">
          {issue.body}
        </p>
      </button>
      <div className="mt-4 flex items-center justify-between gap-3 border-t border-border/60 pt-3">
        <p className="text-[11px] text-muted-foreground">
          Updated{" "}
          {new Intl.DateTimeFormat(undefined, {
            hour: "numeric",
            minute: "2-digit",
          }).format(issue.updatedAt)}
        </p>
        {canStart ? (
          <Button
            disabled={startPending}
            onClick={() => onIssueStart(issue._id, issue.number, issue.title)}
            size="sm"
            type="button"
            variant="outline"
          >
            {startPending ? (
              <LoaderCircle className="animate-spin" data-icon="inline-start" />
            ) : (
              <Bot data-icon="inline-start" />
            )}
            {startPending ? "Starting" : "Start work"}
          </Button>
        ) : null}
      </div>
    </article>
  );
};

const IssueList = ({
  issues,
  onIssueSelect,
  onIssueStart,
  pendingAction,
  selectedId,
}: {
  readonly issues: readonly Doc<"projectIssues">[] | undefined;
  readonly onIssueSelect: (issueId: Id<"projectIssues">) => void;
  readonly onIssueStart: IssueCardProps["onIssueStart"];
  readonly pendingAction: string | null;
  readonly selectedId: Id<"projectIssues"> | null;
}) => {
  if (issues === undefined) {
    return <LoadingLine label="Loading issues" />;
  }
  if (issues.length === 0) {
    return (
      <div className="border border-dashed border-border p-7 text-center">
        <Bot className="mx-auto size-5 text-muted-foreground" />
        <p className="mt-3 text-sm font-medium">
          No issues in this project yet
        </p>
        <p className="mx-auto mt-1 max-w-xs text-xs leading-5 text-muted-foreground">
          Create a small, outcome-shaped issue and it will become the first
          visible loop.
        </p>
      </div>
    );
  }
  return (
    <div className="space-y-3">
      {issues.map((issue) => (
        <IssueCard
          issue={issue}
          key={issue._id}
          onIssueSelect={onIssueSelect}
          onIssueStart={onIssueStart}
          pendingAction={pendingAction}
          selected={issue._id === selectedId}
        />
      ))}
    </div>
  );
};

const Stat = ({
  label,
  tone,
  value,
}: {
  readonly label: string;
  readonly tone: string;
  readonly value: number;
}) => (
  <div className={`border border-border/70 p-3 ${tone}`}>
    <p className="text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
      {label}
    </p>
    <p className="mt-1 text-2xl font-semibold tracking-tight">{value}</p>
  </div>
);

const ProjectStats = ({
  summary,
}: {
  readonly summary: ProjectIssueSummary;
}) => (
  <div className="grid grid-cols-3 gap-2 sm:gap-3">
    <Stat label="Active" tone="bg-blue-500/5" value={summary.active} />
    <Stat label="Needs you" tone="bg-orange-500/5" value={summary.needsInput} />
    <Stat label="Shipped" tone="bg-emerald-500/5" value={summary.completed} />
  </div>
);

interface IssueDetailProps {
  readonly issue: Doc<"projectIssues"> | undefined;
  readonly onOpenPullRequest: (url: string) => void;
  readonly onIssueStart: (
    issueId: Id<"projectIssues">,
    issueNumber: number,
    title: string
  ) => void;
  readonly pendingAction: string | null;
  readonly projectLoop: ProjectLoopView | null;
}

const IssueDetail = ({
  issue,
  onOpenPullRequest,
  onIssueStart,
  pendingAction,
  projectLoop,
}: IssueDetailProps) => {
  if (!issue || !projectLoop) {
    return (
      <aside className="border border-dashed border-border p-6 lg:sticky lg:top-6">
        <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
          Selected work
        </p>
        <h2 className="mt-2 text-lg font-semibold">
          Choose an issue to inspect its loop
        </h2>
        <p className="mt-2 text-sm leading-6 text-muted-foreground">
          Progress, verification, activity, and review artifacts will stay
          together here.
        </p>
      </aside>
    );
  }

  const canStart = issue.status === "open" || issue.status === "failed";
  const startPending = pendingAction === `issue:${issue._id}`;

  return (
    <aside className="space-y-4 lg:sticky lg:top-6">
      <section className="border border-border/70 bg-card/60 p-5 shadow-[0_14px_32px_-24px_rgb(0_0_0/0.45)]">
        <div className="flex items-start justify-between gap-4">
          <div>
            <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
              Issue #{issue.number}
            </p>
            <h2 className="mt-2 text-xl font-semibold leading-7 tracking-tight">
              {issue.title}
            </h2>
          </div>
          <span
            className={`rounded-full px-2 py-1 text-[10px] font-semibold ${statusClasses[issue.status]}`}
          >
            {formatStatus(issue.status)}
          </span>
        </div>
        <p className="mt-3 text-sm leading-6 text-muted-foreground">
          {issue.body}
        </p>

        <div className="mt-5">
          <div className="flex items-center justify-between gap-3 text-xs font-medium">
            <span>{projectLoop.progress}% complete</span>
            <span className="text-muted-foreground">
              {projectLoop.status.label}
            </span>
          </div>
          <div className="mt-2 h-2 bg-muted">
            <div
              className="h-full bg-blue-600 transition-[width] dark:bg-blue-400"
              style={{ width: `${projectLoop.progress}%` }}
            />
          </div>
        </div>

        <div className="mt-5 border-t border-border/70 pt-4">
          <p className="text-[10px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
            Current state
          </p>
          <p className="mt-2 text-sm leading-6">{projectLoop.currentState}</p>
        </div>

        <div className="mt-4 flex items-start gap-3 border border-lime-500/25 bg-lime-400/10 p-3">
          <ArrowUpRight className="mt-0.5 size-4 shrink-0 text-lime-700 dark:text-lime-300" />
          <div>
            <p className="text-[10px] font-semibold uppercase tracking-[0.12em] text-lime-800 dark:text-lime-200">
              Next move
            </p>
            <p className="mt-1 text-sm font-medium">{projectLoop.nextAction}</p>
          </div>
        </div>

        {canStart ? (
          <Button
            className="mt-4 w-full"
            disabled={startPending}
            onClick={() => onIssueStart(issue._id, issue.number, issue.title)}
            type="button"
          >
            {startPending ? (
              <LoaderCircle className="animate-spin" data-icon="inline-start" />
            ) : (
              <Bot data-icon="inline-start" />
            )}
            {startPending
              ? "Starting project manager"
              : "Start project manager"}
          </Button>
        ) : null}
      </section>

      <section className="border border-border/70 bg-card/45 p-5">
        <div className="flex items-center justify-between gap-3">
          <div>
            <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
              Verification
            </p>
            <h3 className="mt-1 text-base font-semibold">
              Evidence earns the next step
            </h3>
          </div>
          <CircleAlert
            className={`size-4 ${verificationIconClass(projectLoop.verification)}`}
          />
        </div>
        <p className="mt-2 text-xs leading-5 text-muted-foreground">
          {projectLoop.verificationNote}
        </p>
        <div className="mt-4 space-y-2">
          {projectLoop.verificationChecks.map((check) => (
            <div
              className="flex items-start gap-3 border border-border/60 p-3"
              key={check.label}
            >
              <span
                className={`mt-0.5 grid size-4 place-items-center rounded-full ${checkStateClass(check.state)}`}
              >
                <span className="text-[9px]">
                  {check.state === "complete" ? "✓" : ""}
                </span>
              </span>
              <div className="min-w-0">
                <p className="text-xs font-medium">{check.label}</p>
                <p className="mt-0.5 text-[11px] leading-4 text-muted-foreground">
                  {check.detail}
                </p>
              </div>
            </div>
          ))}
        </div>
      </section>

      <section className="border border-border/70 bg-card/45 p-5">
        <div className="flex items-center justify-between gap-3">
          <div>
            <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
              Gitea artifact
            </p>
            <h3 className="mt-1 text-base font-semibold">
              Pull request review
            </h3>
          </div>
          <GitPullRequest className="size-4 text-muted-foreground" />
        </div>
        {projectLoop.pullRequest.state === "available" &&
        projectLoop.pullRequest.reviewUrl ? (
          <div className="mt-4 border border-emerald-500/25 bg-emerald-500/10 p-3">
            <p className="text-sm font-medium">
              {projectLoop.pullRequest.number
                ? `PR #${projectLoop.pullRequest.number} is ready for review`
                : "Pull request is ready for review"}
            </p>
            <p className="mt-1 text-xs leading-5 text-muted-foreground">
              Verification evidence is attached to this project loop.
            </p>
            <Button
              className="mt-3"
              onClick={() =>
                onOpenPullRequest(projectLoop.pullRequest.reviewUrl as string)
              }
              type="button"
              variant="outline"
            >
              <ExternalLink data-icon="inline-start" />
              Review changes
            </Button>
          </div>
        ) : (
          <div className="mt-4 border border-dashed border-border p-3">
            <p className="text-sm font-medium">Review link pending</p>
            <p className="mt-1 text-xs leading-5 text-muted-foreground">
              The slot is ready for a Gitea pull request when the agent
              publishes one. The rest of the run remains observable now.
            </p>
          </div>
        )}
      </section>

      <section className="border border-border/70 bg-card/45 p-5">
        <div className="flex items-center gap-2">
          <Sparkles className="size-3.5 text-lime-600 dark:text-lime-300" />
          <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
            Recent activity
          </p>
        </div>
        <div className="mt-4 space-y-4">
          {projectLoop.activity.map((item) => (
            <div className="flex gap-3" key={`${item.label}-${item.time}`}>
              <div className="mt-1.5 size-1.5 shrink-0 rounded-full bg-foreground/50" />
              <div className="min-w-0">
                <p className="text-xs font-medium">{item.label}</p>
                <p className="mt-0.5 text-xs leading-5 text-muted-foreground">
                  {item.detail}
                </p>
                <p className="mt-1 text-[10px] text-muted-foreground/75">
                  {item.time}
                </p>
              </div>
            </div>
          ))}
        </div>
      </section>
    </aside>
  );
};

export const ProjectWorkspacePage = () => {
  const workspace = useProjectWorkspace();
  const projectSource = workspace.selectedProject?.sources[0];
  const handleIssueBodyChange = workspace.setIssueBody;
  const handleIssueSelect = workspace.setSelectedIssueId;
  const handleIssueStart = workspace.startIssue;
  const handleIssueSubmit = workspace.raiseIssue;
  const handleIssueTitleChange = workspace.setIssueTitle;
  const handleProjectSelect = workspace.setSelectedProjectId;
  const handleRepositoryChange = workspace.setRepository;
  const handleRepositorySubmit = workspace.connectRepository;

  return (
    <main className="min-h-svh bg-background text-foreground">
      <header className="border-b border-border/70 bg-background/90 backdrop-blur">
        <div className="mx-auto flex max-w-[1540px] items-center justify-between gap-4 px-4 py-3 sm:px-6">
          <div className="flex min-w-0 items-center gap-3">
            <div className="grid size-9 shrink-0 place-items-center bg-lime-400 text-black">
              <span className="text-base font-semibold">Z</span>
            </div>
            <div className="min-w-0">
              <div className="flex items-center gap-2">
                <p className="text-sm font-semibold">Zopu</p>
                <span className="size-1.5 rounded-full bg-emerald-500" />
                <span className="text-xs text-muted-foreground">
                  Project loop
                </span>
              </div>
              <p className="truncate text-[11px] text-muted-foreground">
                Connect context, move issues, review outcomes.
              </p>
            </div>
          </div>
          <UserMenu />
        </div>
      </header>

      <div className="mx-auto grid min-h-[calc(100svh-65px)] max-w-[1540px] md:grid-cols-[250px_minmax(0,1fr)]">
        <div className="flex min-h-0 flex-col">
          <RepositoryForm
            busy={workspace.pendingAction === "connect"}
            onRepositoryChange={handleRepositoryChange}
            onRepositorySubmit={handleRepositorySubmit}
            value={workspace.repository}
          />
          <ProjectSidebar
            onProjectSelect={handleProjectSelect}
            projects={workspace.projects}
            selectedId={workspace.selectedProjectId}
          />
        </div>

        <div className="min-w-0 px-4 py-5 sm:px-6 sm:py-7 lg:px-8">
          {workspace.error ? (
            <div className="mb-5 flex items-start gap-3 border border-destructive/35 bg-destructive/10 p-3 text-sm text-destructive">
              <CircleAlert className="mt-0.5 size-4 shrink-0" />
              <p>{workspace.error}</p>
            </div>
          ) : null}

          {workspace.selectedProject ? (
            <div className="space-y-6">
              <section className="flex flex-col gap-4 border-b border-border/70 pb-5 lg:flex-row lg:items-end lg:justify-between">
                <div className="min-w-0">
                  <div className="flex flex-wrap items-center gap-2 text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
                    <span>Project workspace</span>
                    <span>/</span>
                    <span className="truncate">
                      {projectSource?.host ?? "Repository"}
                    </span>
                  </div>
                  <h1 className="mt-2 text-3xl font-semibold sm:text-4xl">
                    {workspace.selectedProject.name}
                  </h1>
                  <p className="mt-2 flex items-center gap-2 text-sm text-muted-foreground">
                    <FolderGit2 className="size-4" />
                    <span className="truncate">
                      {projectSource
                        ? `${projectSource.host}/${projectSource.repositoryPath}`
                        : "No repository source"}
                    </span>
                  </p>
                </div>
                {projectSource ? (
                  <Button
                    className="w-full sm:w-auto"
                    onClick={() =>
                      window.open(
                        projectSource.url,
                        "_blank",
                        "noopener,noreferrer"
                      )
                    }
                    type="button"
                    variant="outline"
                  >
                    <ExternalLink data-icon="inline-start" />
                    Open repository
                  </Button>
                ) : null}
              </section>

              <section className="grid gap-3 lg:grid-cols-[minmax(0,1fr)_minmax(300px,0.72fr)]">
                <div className="border border-border/70 bg-blue-500/5 p-5 sm:p-6">
                  <div className="flex flex-wrap items-center justify-between gap-3">
                    <div className="flex items-center gap-2">
                      <span className="grid size-7 place-items-center rounded-full bg-blue-600 text-white dark:bg-blue-400 dark:text-blue-950">
                        <Bot className="size-3.5" />
                      </span>
                      <p className="text-sm font-semibold">Work in motion</p>
                    </div>
                    <span className="rounded-full bg-blue-500/15 px-2 py-1 text-[10px] font-semibold text-blue-700 dark:text-blue-300">
                      Context attached
                    </span>
                  </div>
                  <h2 className="mt-7 max-w-xl text-2xl font-semibold tracking-tight sm:text-3xl">
                    Make the next useful move visible.
                  </h2>
                  <p className="mt-2 max-w-2xl text-sm leading-6 text-muted-foreground">
                    Every issue carries the project context, agent run,
                    verification evidence, and review artifact as one durable
                    loop.
                  </p>
                  <div className="mt-6 flex flex-wrap items-center gap-2 text-[10px] font-semibold uppercase tracking-[0.1em] text-muted-foreground">
                    {[
                      ["01", "Issue"],
                      ["02", "Run"],
                      ["03", "Verify"],
                      ["04", "Review"],
                    ].map(([number, label]) => (
                      <div className="flex items-center gap-2" key={number}>
                        <span className="grid size-5 place-items-center rounded-full bg-background text-[9px] text-foreground">
                          {number}
                        </span>
                        <span>{label}</span>
                        {number === "04" ? null : (
                          <span className="px-1 text-border">/</span>
                        )}
                      </div>
                    ))}
                  </div>
                </div>
                <div className="border border-border/70 bg-card/50 p-4 sm:p-5">
                  <div className="flex items-center justify-between gap-3">
                    <div>
                      <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
                        Project pulse
                      </p>
                      <p className="mt-1 text-sm font-semibold">
                        No hidden queue
                      </p>
                    </div>
                    <Sparkles className="size-4 text-lime-600 dark:text-lime-300" />
                  </div>
                  <p className="mt-4 text-sm leading-6 text-muted-foreground">
                    The cards below are the current durable issues. Open one to
                    follow the work, not a transient chat session.
                  </p>
                  <div className="mt-5">
                    <ProjectStats summary={workspace.issueSummary} />
                  </div>
                </div>
              </section>

              <IssueComposer
                body={workspace.issueBody}
                busy={workspace.pendingAction === "issue"}
                onIssueBodyChange={handleIssueBodyChange}
                onIssueSubmit={handleIssueSubmit}
                onIssueTitleChange={handleIssueTitleChange}
                title={workspace.issueTitle}
              />

              <div className="grid items-start gap-6 lg:grid-cols-[minmax(0,1.05fr)_minmax(350px,0.8fr)]">
                <section
                  aria-labelledby="active-work-heading"
                  className="min-w-0"
                >
                  <div className="mb-3 flex items-end justify-between gap-3">
                    <div>
                      <p className="text-[11px] font-semibold uppercase tracking-[0.12em] text-muted-foreground">
                        Durable queue
                      </p>
                      <h2
                        className="mt-1 text-lg font-semibold"
                        id="active-work-heading"
                      >
                        Issues in this project
                      </h2>
                    </div>
                    <span className="text-xs text-muted-foreground">
                      {workspace.issueSummary.total} total
                    </span>
                  </div>
                  <IssueList
                    issues={workspace.issues}
                    onIssueSelect={handleIssueSelect}
                    onIssueStart={handleIssueStart}
                    pendingAction={workspace.pendingAction}
                    selectedId={workspace.selectedIssueId}
                  />
                </section>

                <IssueDetail
                  issue={workspace.selectedIssue}
                  onOpenPullRequest={(url) =>
                    window.open(url, "_blank", "noopener,noreferrer")
                  }
                  onIssueStart={handleIssueStart}
                  pendingAction={workspace.pendingAction}
                  projectLoop={workspace.projectLoop}
                />
              </div>
            </div>
          ) : (
            <section className="grid min-h-[65svh] place-items-center border border-dashed border-border p-8 text-center">
              <div className="max-w-md">
                <div className="mx-auto grid size-12 place-items-center bg-lime-400 text-black">
                  <GitFork className="size-5" />
                </div>
                <h1 className="mt-5 text-2xl font-semibold tracking-tight">
                  Connect a project to start the loop
                </h1>
                <p className="mt-2 text-sm leading-6 text-muted-foreground">
                  Import a repository, keep its context attached, then turn a
                  clear outcome into an issue that can be started, verified, and
                  reviewed.
                </p>
              </div>
            </section>
          )}
        </div>
      </div>
    </main>
  );
};
