import { useQuery } from '@tanstack/react-query';
import { Link } from '@tanstack/react-router';
import { useDeferredValue, useState } from 'react';

import { Alert, AlertDescription, AlertTitle } from '../cadence-ui/components/alert';
import { Badge } from '../cadence-ui/components/badge';
import { Button } from '../cadence-ui/components/button';
import {
  Card,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from '../cadence-ui/components/card';
import {
  Dialog,
  DialogContent,
  DialogDescription,
  DialogHeader,
  DialogTitle,
  DialogTrigger,
} from '../cadence-ui/components/dialog';
import { Input } from '../cadence-ui/components/input';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '../cadence-ui/components/tabs';
import { Textarea } from '../cadence-ui/components/textarea';
import { cn } from '../cadence-ui/lib/cn';
import {
  type BlockedQueueItem,
  type BlockedTask,
  type Message,
  type Run,
  type RunDetail,
  type RunListItem,
  type Task,
  type ThreadDetail,
  getRunDetail,
  getThreadDetail,
  listBlockedQueue,
  listRuns,
} from '../lib/api';
import {
  formatDateTime,
  formatJson,
  hasStructuredData,
  pluralize,
  statusLabel,
  uniqueCount,
} from '../lib/format';

const terminalStatuses = new Set(['cancelled', 'completed', 'done', 'failed']);

export function RunsPage() {
  const runsQuery = useQuery({
    queryKey: ['runs'],
    queryFn: listRuns,
    refetchInterval: 15_000,
  });
  const [search, setSearch] = useState('');
  const deferredSearch = useDeferredValue(search.trim().toLowerCase());

  const runs = runsQuery.data ?? [];
  const filteredRuns = runs.filter((item) => matchesRun(item, deferredSearch));
  const totalRuns = runs.length;
  const activeRuns = runs.filter((item) => !terminalStatuses.has(item.run.status)).length;
  const blockedTasks = runs.reduce((sum, item) => sum + (item.task_counts.blocked ?? 0), 0);
  const totalTasks = runs.reduce((sum, item) => sum + item.total_tasks, 0);

  return (
    <div className="space-y-6">
      <PageHero
        eyebrow="Runs overview"
        title="Watch the scheduler shape work across every active run."
        description="This surface is read-only for now: scan run health, task distribution, and where blocked questions are starting to accumulate."
      >
        <Input
          aria-label="Filter runs"
          className="w-full md:max-w-sm"
          onChange={(event) => setSearch(event.target.value)}
          placeholder="Filter by run id, goal, or summary"
          value={search}
        />
      </PageHero>

      <MetricsGrid>
        <MetricCard
          label="Tracked runs"
          value={String(totalRuns)}
          caption={`${activeRuns} currently active`}
          tone="default"
        />
        <MetricCard
          label="Total tasks"
          value={String(totalTasks)}
          caption={pluralize(totalTasks, 'task')}
          tone="subtle"
        />
        <MetricCard
          label="Blocked tasks"
          value={String(blockedTasks)}
          caption={blockedTasks > 0 ? 'Need operator attention' : 'No current blockers'}
          tone={blockedTasks > 0 ? 'accent' : 'subtle'}
        />
      </MetricsGrid>

      {runsQuery.isLoading ? (
        <LoadingState count={4} />
      ) : runsQuery.isError ? (
        <QueryErrorState
          description="The runs endpoint did not return data. Make sure the operator API is running and the dev server can reach it."
          onRetry={() => void runsQuery.refetch()}
          title="Unable to load orchestration runs"
        />
      ) : filteredRuns.length === 0 ? (
        <EmptyState
          description={
            deferredSearch
              ? 'No runs matched the current filter. Try a run id, goal phrase, or summary keyword.'
              : 'No runs are present yet. Once the scheduler has state, this page will show it here.'
          }
          title={deferredSearch ? 'No matching runs' : 'No runs yet'}
        />
      ) : (
        <div className="grid gap-4 xl:grid-cols-2">
          {filteredRuns.map((item) => (
            <RunSummaryCard key={item.run.run_id} item={item} />
          ))}
        </div>
      )}
    </div>
  );
}

export function BlockedQueuePage() {
  const blockedQuery = useQuery({
    queryKey: ['blocked-queue'],
    queryFn: listBlockedQueue,
    refetchInterval: 10_000,
  });
  const [search, setSearch] = useState('');
  const deferredSearch = useDeferredValue(search.trim().toLowerCase());

  const blockedItems = blockedQuery.data ?? [];
  const filteredItems = blockedItems.filter((item) => matchesBlockedItem(item, deferredSearch));
  const impactedRuns = uniqueCount(blockedItems, (item) => item.run.run_id);
  const waitingWorkers = uniqueCount(blockedItems, (item) => item.attempt.assigned_to);

  return (
    <div className="space-y-6">
      <PageHero
        eyebrow="Blocked queue"
        title="Surface every worker question before it stalls the run."
        description="This queue aggregates blocked tasks across all runs using the current read-only API. It is the best place to spot response bottlenecks."
      >
        <Input
          aria-label="Filter blocked tasks"
          className="w-full md:max-w-sm"
          onChange={(event) => setSearch(event.target.value)}
          placeholder="Filter by run, task, worker, or question"
          value={search}
        />
      </PageHero>

      <MetricsGrid>
        <MetricCard
          label="Blocked tasks"
          value={String(blockedItems.length)}
          caption={blockedItems.length > 0 ? 'Awaiting operator input' : 'Queue is clear'}
          tone={blockedItems.length > 0 ? 'accent' : 'subtle'}
        />
        <MetricCard
          label="Impacted runs"
          value={String(impactedRuns)}
          caption={pluralize(impactedRuns, 'run')}
          tone="default"
        />
        <MetricCard
          label="Workers waiting"
          value={String(waitingWorkers)}
          caption={pluralize(waitingWorkers, 'worker')}
          tone="subtle"
        />
      </MetricsGrid>

      {blockedQuery.isLoading ? (
        <LoadingState count={3} />
      ) : blockedQuery.isError ? (
        <QueryErrorState
          description="The queue view composes run summaries with per-run blocked endpoints. Check that the operator API is reachable."
          onRetry={() => void blockedQuery.refetch()}
          title="Unable to load the blocked queue"
        />
      ) : filteredItems.length === 0 ? (
        <EmptyState
          description={
            deferredSearch
              ? 'No blocked tasks matched the current filter.'
              : 'No blocked tasks are present. This is where waiting questions will appear once runs start blocking.'
          }
          title={deferredSearch ? 'No matching blocked tasks' : 'Queue is clear'}
        />
      ) : (
        <div className="grid gap-4">
          {filteredItems.map((item) => (
            <BlockedTaskCard key={`${item.run.run_id}-${item.task.task_id}-${item.attempt.attempt_no}`} item={item} />
          ))}
        </div>
      )}
    </div>
  );
}

export function RunDetailPage({ runId }: { runId: string }) {
  const runQuery = useQuery({
    queryKey: ['run', runId],
    queryFn: () => getRunDetail(runId),
    refetchInterval: 10_000,
  });
  const [search, setSearch] = useState('');
  const deferredSearch = useDeferredValue(search.trim().toLowerCase());

  if (runQuery.isLoading) {
    return <LoadingState count={4} />;
  }

  if (runQuery.isError) {
    return (
      <QueryErrorState
        description="The selected run could not be loaded. It may have been removed, or the API may not be reachable."
        onRetry={() => void runQuery.refetch()}
        title={`Unable to load run ${runId}`}
      />
    );
  }

  const detail = runQuery.data;
  if (!detail) {
    return (
      <QueryErrorState
        description="The API returned an empty run detail payload."
        onRetry={() => void runQuery.refetch()}
        title={`Missing run data for ${runId}`}
      />
    );
  }

  const filteredTasks = detail.tasks.filter((task) => matchesTask(task, deferredSearch));
  const blockedByTaskID = new Map(detail.blocked_tasks.map((item) => [item.task.task_id, item] as const));
  const groupedTasks = groupTasks(filteredTasks);
  const statusEntries = sortTaskCounts(detail.task_counts);

  return (
    <div className="space-y-6">
      <Card tone={detail.blocked_tasks.length > 0 ? 'accent' : 'default'}>
        <CardHeader className="gap-4">
          <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
            <div className="space-y-3">
              <div className="flex flex-wrap items-center gap-2">
                <Badge tone="primary">{detail.run.run_id}</Badge>
                <StatusBadge status={detail.run.status} />
                <Badge tone="neutral" variant="outline">
                  {detail.total_tasks} total tasks
                </Badge>
              </div>
              <CardTitle className="type-display text-[clamp(2.2rem,4vw,4rem)] leading-[0.92] tracking-[-0.05em]">
                {detail.run.goal}
              </CardTitle>
              <CardDescription className="max-w-3xl text-base leading-7">
                {detail.run.summary}
              </CardDescription>
            </div>

            <div className="grid gap-3 sm:grid-cols-2">
              <CompactStat label="Created" value={formatDateTime(detail.run.created_at)} />
              <CompactStat label="Updated" value={formatDateTime(detail.run.updated_at)} />
              <CompactStat
                label="Blocked now"
                value={String(detail.blocked_tasks.length)}
              />
              <CompactStat label="Run id" value={detail.run.run_id} />
            </div>
          </div>
        </CardHeader>
        <CardFooter className="flex flex-wrap justify-between gap-3">
          <div className="flex flex-wrap gap-2">
            {statusEntries.map(([status, count]) => (
              <Badge key={status} tone={badgeToneForStatus(status)} variant="outline">
                {statusLabel(status)} · {count}
              </Badge>
            ))}
          </div>
          <div className="flex flex-wrap gap-2">
            <Button asChild size="sm" variant="ghost">
              <Link to="/">Back to runs</Link>
            </Button>
            <Button asChild size="sm" variant="subtle">
              <Link to="/blocked">Global blocked queue</Link>
            </Button>
          </div>
        </CardFooter>
      </Card>

      {detail.blocked_tasks.length > 0 ? (
        <Alert
          icon={<SignalIcon />}
          variant="warning"
        >
          <AlertTitle>{detail.blocked_tasks.length} blocked {pluralize(detail.blocked_tasks.length, 'task')}</AlertTitle>
          <AlertDescription>
            This run currently has work waiting on a reply. Open the blocked tab for the question summaries and thread links.
          </AlertDescription>
        </Alert>
      ) : null}

      <Tabs defaultValue="tasks">
        <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
          <TabsList>
            <TabsTrigger value="overview">Overview</TabsTrigger>
            <TabsTrigger value="tasks">Task board</TabsTrigger>
            <TabsTrigger value="blocked">
              Blocked
              <span className="ml-1 rounded-full bg-[color-mix(in_oklch,var(--color-primary)_16%,transparent)] px-1.5 py-0.5 text-[0.68rem] text-[var(--color-primary)]">
                {detail.blocked_tasks.length}
              </span>
            </TabsTrigger>
          </TabsList>

          <Input
            aria-label="Filter run tasks"
            className="w-full lg:max-w-sm"
            onChange={(event) => setSearch(event.target.value)}
            placeholder="Filter tasks by id, title, summary, or owner"
            value={search}
          />
        </div>

        <TabsContent value="overview">
          <div className="grid gap-4 xl:grid-cols-[minmax(0,1.4fr)_minmax(20rem,0.8fr)]">
            <Card tone="subtle">
              <CardHeader>
                <CardTitle>Run posture</CardTitle>
                <CardDescription>
                  High-level task distribution across the current run state.
                </CardDescription>
              </CardHeader>
              <CardContent className="grid gap-3 sm:grid-cols-2 xl:grid-cols-3">
                <MetricCard
                  label="Total tasks"
                  value={String(detail.total_tasks)}
                  caption={pluralize(detail.total_tasks, 'task')}
                  tone="default"
                />
                <MetricCard
                  label="Blocked"
                  value={String(detail.blocked_tasks.length)}
                  caption={detail.blocked_tasks.length > 0 ? 'Needs answer' : 'No blockers'}
                  tone={detail.blocked_tasks.length > 0 ? 'accent' : 'subtle'}
                />
                <MetricCard
                  label="Status buckets"
                  value={String(statusEntries.length)}
                  caption={pluralize(statusEntries.length, 'state')}
                  tone="subtle"
                />
              </CardContent>
            </Card>

            <Card>
              <CardHeader>
                <CardTitle>Status mix</CardTitle>
                <CardDescription>Current task counts grouped by orchestration status.</CardDescription>
              </CardHeader>
              <CardContent className="grid gap-3">
                {statusEntries.map(([status, count]) => (
                  <div
                    className="flex items-center justify-between rounded-[1rem] border border-[color-mix(in_oklch,var(--color-border)_72%,transparent)] bg-[color-mix(in_oklch,var(--color-surface)_78%,white_22%)] px-4 py-3"
                    key={status}
                  >
                    <div className="flex items-center gap-3">
                      <StatusBadge status={status} />
                      <span className="text-sm text-[var(--color-foreground)]">{statusLabel(status)}</span>
                    </div>
                    <span className="text-sm font-semibold text-[var(--color-foreground)]">{count}</span>
                  </div>
                ))}
              </CardContent>
            </Card>
          </div>
        </TabsContent>

        <TabsContent value="tasks">
          {filteredTasks.length === 0 ? (
            <EmptyState
              description={
                deferredSearch
                  ? 'No tasks matched the current filter.'
                  : 'This run has no tasks yet.'
              }
              title={deferredSearch ? 'No matching tasks' : 'No tasks in this run'}
            />
          ) : (
            <div className="grid gap-4 xl:grid-cols-3">
              {groupedTasks.map(([status, tasks]) => (
                <Card key={status} tone={status === 'blocked' ? 'accent' : 'subtle'}>
                  <CardHeader>
                    <div className="flex items-center justify-between gap-3">
                      <div className="space-y-1">
                        <CardTitle>{statusLabel(status)}</CardTitle>
                        <CardDescription>{pluralize(tasks.length, 'task')}</CardDescription>
                      </div>
                      <StatusBadge status={status} />
                    </div>
                  </CardHeader>
                  <CardContent className="grid gap-3">
                    {tasks.map((task) => (
                      <TaskCard
                        blockedTask={blockedByTaskID.get(task.task_id)}
                        key={task.task_id}
                        task={task}
                      />
                    ))}
                  </CardContent>
                </Card>
              ))}
            </div>
          )}
        </TabsContent>

        <TabsContent value="blocked">
          {detail.blocked_tasks.length === 0 ? (
            <EmptyState
              description="No tasks in this run are currently waiting on a reply."
              title="No blocked tasks"
            />
          ) : (
            <div className="grid gap-4">
              {detail.blocked_tasks.map((item) => (
                <BlockedTaskCard
                  item={{
                    ...item,
                    run: detail.run,
                  }}
                  key={`${item.task.task_id}-${item.attempt.attempt_no}`}
                />
              ))}
            </div>
          )}
        </TabsContent>
      </Tabs>
    </div>
  );
}

export function ThreadTimelinePage({ threadId }: { threadId: string }) {
  const threadQuery = useQuery({
    queryKey: ['thread', threadId],
    queryFn: () => getThreadDetail(threadId),
    refetchInterval: 5_000,
  });

  if (threadQuery.isLoading) {
    return <LoadingState count={3} />;
  }

  if (threadQuery.isError) {
    return (
      <QueryErrorState
        description="The selected thread could not be loaded. Make sure the thread id is still valid and the operator API can reach the shared SQLite database."
        onRetry={() => void threadQuery.refetch()}
        title={`Unable to load thread ${threadId}`}
      />
    );
  }

  const detail = threadQuery.data;
  if (!detail) {
    return (
      <QueryErrorState
        description="The API returned an empty thread payload."
        onRetry={() => void threadQuery.refetch()}
        title={`Missing thread data for ${threadId}`}
      />
    );
  }

  const artifactCount = detail.messages.reduce((sum, message) => sum + message.artifacts.length, 0);

  return (
    <div className="space-y-6">
      <Card tone={detail.thread.status === 'blocked' ? 'accent' : 'default'}>
        <CardHeader className="gap-4">
          <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
            <div className="space-y-3">
              <div className="flex flex-wrap items-center gap-2">
                <Badge tone="primary">{detail.thread.thread_id}</Badge>
                <StatusBadge status={detail.thread.status} />
                <PriorityBadge priority={detail.thread.priority} />
              </div>
              <CardTitle className="type-display text-[clamp(2.1rem,3.6vw,3.4rem)] leading-[0.94] tracking-[-0.05em]">
                {detail.thread.subject}
              </CardTitle>
              <CardDescription className="max-w-3xl text-base leading-7">
                Leader-to-worker timeline for task {detail.thread.task_id} in run {detail.thread.run_id}.
              </CardDescription>
            </div>

            <div className="grid gap-3 sm:grid-cols-2">
              <CompactStat label="Created by" value={detail.thread.created_by} />
              <CompactStat label="Assigned to" value={detail.thread.assigned_to} />
              <CompactStat label="Opened" value={formatDateTime(detail.thread.created_at)} />
              <CompactStat label="Updated" value={formatDateTime(detail.thread.updated_at)} />
            </div>
          </div>
        </CardHeader>
        <CardFooter className="flex flex-wrap justify-between gap-3">
          <div className="flex flex-wrap gap-2">
            <Button asChild size="sm" variant="ghost">
              <Link params={{ runId: detail.thread.run_id }} to="/runs/$runId">
                Back to run
              </Link>
            </Button>
            <Button asChild size="sm" variant="subtle">
              <Link to="/blocked">Blocked queue</Link>
            </Button>
          </div>
          <div className="flex flex-wrap gap-2">
            <Badge variant="outline">{pluralize(detail.messages.length, 'message')}</Badge>
            <Badge variant="outline">{pluralize(artifactCount, 'artifact')}</Badge>
          </div>
        </CardFooter>
      </Card>

      {detail.thread.status === 'blocked' ? (
        <Alert icon={<SignalIcon />} variant="warning">
          <AlertTitle>Thread is blocked</AlertTitle>
          <AlertDescription>
            The active worker is waiting on an answer in this thread. Review the latest question before replying through the CLI or future operator actions.
          </AlertDescription>
        </Alert>
      ) : null}

      {detail.messages.length === 0 ? (
        <EmptyState
          description="This thread exists, but it does not have any messages yet."
          title="No timeline messages"
        />
      ) : (
        <div className="grid gap-4">
          {detail.messages.map((message, index) => (
            <ThreadMessageCard
              index={index}
              key={message.message_id}
              message={message}
              total={detail.messages.length}
            />
          ))}
        </div>
      )}
    </div>
  );
}

function PageHero({
  eyebrow,
  title,
  description,
  children,
}: {
  eyebrow: string;
  title: string;
  description: string;
  children?: React.ReactNode;
}) {
  return (
    <section className="grid gap-4 xl:grid-cols-[minmax(0,1.25fr)_minmax(18rem,0.75fr)]">
      <Card tone="accent">
        <CardHeader className="gap-4">
          <div className="space-y-3">
            <p className="text-[0.68rem] font-semibold uppercase tracking-[0.28em] text-[var(--color-primary)]">
              {eyebrow}
            </p>
            <CardTitle className="type-display text-[clamp(2.3rem,5vw,4.6rem)] leading-[0.9] tracking-[-0.06em]">
              {title}
            </CardTitle>
            <CardDescription className="max-w-3xl text-base leading-7">
              {description}
            </CardDescription>
          </div>
        </CardHeader>
      </Card>

      <Card tone="subtle">
        <CardHeader>
          <CardTitle>Operator filter</CardTitle>
          <CardDescription>
            Narrow the current surface without leaving the page.
          </CardDescription>
        </CardHeader>
        <CardContent>{children}</CardContent>
      </Card>
    </section>
  );
}

function MetricsGrid({ children }: { children: React.ReactNode }) {
  return <section className="grid gap-4 md:grid-cols-2 xl:grid-cols-3">{children}</section>;
}

function MetricCard({
  label,
  value,
  caption,
  tone,
}: {
  label: string;
  value: string;
  caption: string;
  tone: 'accent' | 'default' | 'subtle';
}) {
  return (
    <Card tone={tone}>
      <CardContent className="space-y-3 p-6">
        <p className="text-[0.72rem] font-semibold uppercase tracking-[0.24em] text-[var(--color-muted-foreground)]">
          {label}
        </p>
        <div className="flex items-end justify-between gap-3">
          <p className="type-display text-[clamp(2rem,4vw,3.2rem)] leading-none tracking-[-0.05em] text-[var(--color-foreground)]">
            {value}
          </p>
          <span className="text-sm leading-6 text-[var(--color-muted-foreground)]">{caption}</span>
        </div>
      </CardContent>
    </Card>
  );
}

function RunSummaryCard({ item }: { item: RunListItem }) {
  const blockedCount = item.task_counts.blocked ?? 0;

  return (
    <Card interactive tone={blockedCount > 0 ? 'accent' : 'default'}>
      <CardHeader className="gap-4">
        <div className="flex flex-wrap items-center justify-between gap-3">
          <div className="flex flex-wrap items-center gap-2">
            <Badge tone="primary">{item.run.run_id}</Badge>
            <StatusBadge status={item.run.status} />
          </div>
          <span className="text-xs text-[var(--color-muted-foreground)]">
            Updated {formatDateTime(item.run.updated_at)}
          </span>
        </div>
        <div className="space-y-2">
          <CardTitle className="type-display text-[2rem] leading-[0.96] tracking-[-0.05em]">
            {item.run.goal}
          </CardTitle>
          <CardDescription className="text-base leading-7">{item.run.summary}</CardDescription>
        </div>
      </CardHeader>

      <CardContent className="grid gap-3 sm:grid-cols-2">
        <CompactStat label="Tasks" value={String(item.total_tasks)} />
        <CompactStat label="Blocked" value={String(blockedCount)} />
        {sortTaskCounts(item.task_counts).map(([status, count]) => (
          <div
            className="flex items-center justify-between rounded-[1rem] border border-[color-mix(in_oklch,var(--color-border)_72%,transparent)] bg-[color-mix(in_oklch,var(--color-surface)_82%,white_18%)] px-4 py-3"
            key={status}
          >
            <span className="text-sm text-[var(--color-muted-foreground)]">{statusLabel(status)}</span>
            <span className="text-sm font-semibold text-[var(--color-foreground)]">{count}</span>
          </div>
        ))}
      </CardContent>

      <CardFooter className="gap-2">
        <Button asChild size="sm" variant="primary">
          <Link params={{ runId: item.run.run_id }} to="/runs/$runId">
            Open run
          </Link>
        </Button>
        <Button asChild size="sm" variant="ghost">
          <Link to="/blocked">Blocked queue</Link>
        </Button>
      </CardFooter>
    </Card>
  );
}

function TaskCard({
  task,
  blockedTask,
}: {
  task: Task;
  blockedTask?: BlockedTask;
}) {
  return (
    <article className="space-y-4 rounded-[1.25rem] border border-[color-mix(in_oklch,var(--color-border)_72%,transparent)] bg-[color-mix(in_oklch,var(--color-card)_86%,white_14%)] p-4 shadow-[var(--shadow-xs)]">
      <div className="space-y-2">
        <div className="flex flex-wrap items-center gap-2">
          <Badge tone="primary" variant="outline">
            {task.task_id}
          </Badge>
          <StatusBadge status={task.status} />
          <PriorityBadge priority={task.priority} />
        </div>
        <h3 className="text-base font-semibold tracking-[var(--tracking-tight)] text-[var(--color-foreground)]">
          {task.title}
        </h3>
        <p className="text-sm leading-6 text-[var(--color-muted-foreground)]">{task.summary}</p>
      </div>

      <dl className="grid gap-2 text-sm text-[var(--color-muted-foreground)]">
        <div className="flex items-center justify-between gap-3">
          <dt>Owner</dt>
          <dd className="font-medium text-[var(--color-foreground)]">{task.default_to || 'Unassigned'}</dd>
        </div>
        <div className="flex items-center justify-between gap-3">
          <dt>Latest attempt</dt>
          <dd className="font-medium text-[var(--color-foreground)]">{task.latest_attempt_no || 0}</dd>
        </div>
      </dl>

      {blockedTask ? (
        <div className="rounded-[1rem] border border-[color-mix(in_oklch,var(--color-warning)_24%,var(--color-border))] bg-[color-mix(in_oklch,var(--color-warning)_12%,var(--color-card))] p-3">
          <p className="text-[0.68rem] font-semibold uppercase tracking-[0.24em] text-[color-mix(in_oklch,var(--color-warning)_72%,var(--color-foreground))]">
            Waiting on reply
          </p>
          <p className="mt-2 text-sm font-medium text-[var(--color-foreground)]">
            {blockedTask.question.summary}
          </p>
          <p className="mt-1 text-sm leading-6 text-[var(--color-muted-foreground)]">
            {blockedTask.question.body}
          </p>
        </div>
      ) : null}

      <div className="flex flex-wrap gap-2">
        {blockedTask ? (
          <Button asChild size="sm" variant="primary">
            <Link params={{ threadId: blockedTask.attempt.thread_id }} to="/threads/$threadId">
              Open timeline
            </Link>
          </Button>
        ) : null}
        {hasStructuredData(task.acceptance_json) ? (
          <JsonDialog
            description="Acceptance data is shown exactly as returned by the HTTP API."
            label="Acceptance JSON"
            title={`Acceptance for ${task.task_id}`}
            value={task.acceptance_json}
          />
        ) : null}
      </div>
    </article>
  );
}

function BlockedTaskCard({ item }: { item: BlockedQueueItem }) {
  return (
    <Card tone="accent">
      <CardHeader className="gap-4">
        <div className="flex flex-col gap-3 lg:flex-row lg:items-start lg:justify-between">
          <div className="space-y-3">
            <div className="flex flex-wrap items-center gap-2">
              <Badge tone="primary">{item.run.run_id}</Badge>
              <Badge variant="outline">{item.task.task_id}</Badge>
              <PriorityBadge priority={item.task.priority} />
            </div>
            <div className="space-y-2">
              <CardTitle>{item.task.title}</CardTitle>
              <CardDescription className="text-base leading-7">{item.task.summary}</CardDescription>
            </div>
          </div>

          <div className="grid gap-2 text-sm text-[var(--color-muted-foreground)]">
            <div className="flex items-center gap-2">
              <StatusBadge status={item.task.status} />
              <span>attempt {item.attempt.attempt_no}</span>
            </div>
            <span>assigned to {item.attempt.assigned_to}</span>
            <span>{formatDateTime(item.question.created_at)}</span>
          </div>
        </div>
      </CardHeader>

      <CardContent className="grid gap-4 xl:grid-cols-[minmax(0,1.3fr)_minmax(16rem,0.7fr)]">
        <div className="space-y-3 rounded-[1.25rem] border border-[color-mix(in_oklch,var(--color-warning)_26%,var(--color-border))] bg-[color-mix(in_oklch,var(--color-warning)_10%,var(--color-card))] p-4">
          <p className="text-[0.68rem] font-semibold uppercase tracking-[0.24em] text-[color-mix(in_oklch,var(--color-warning)_72%,var(--color-foreground))]">
            Latest question
          </p>
          <h3 className="text-base font-semibold tracking-[var(--tracking-tight)] text-[var(--color-foreground)]">
            {item.question.summary}
          </h3>
          <p className="whitespace-pre-wrap text-sm leading-6 text-[var(--color-muted-foreground)]">
            {item.question.body}
          </p>
        </div>

        <div className="grid gap-3 text-sm">
          <CompactStat label="From" value={item.question.from_agent} />
          <CompactStat label="To" value={item.question.to_agent} />
          <CompactStat label="Thread" value={item.attempt.thread_id} />
        </div>
      </CardContent>

      <CardFooter className="flex flex-wrap gap-2">
        <Button asChild size="sm" variant="primary">
          <Link params={{ runId: item.run.run_id }} to="/runs/$runId">
            Open run
          </Link>
        </Button>
        <Button asChild size="sm" variant="subtle">
          <Link params={{ threadId: item.attempt.thread_id }} to="/threads/$threadId">
            Thread timeline
          </Link>
        </Button>
        {hasStructuredData(item.question.payload_json) ? (
          <JsonDialog
            description="This is the raw question payload returned by the API."
            label="Question payload"
            title={`Payload for ${item.task.task_id}`}
            value={item.question.payload_json}
          />
        ) : null}
      </CardFooter>
    </Card>
  );
}

function ThreadMessageCard({
  index,
  message,
  total,
}: {
  index: number;
  message: Message;
  total: number;
}) {
  return (
    <div className="grid gap-3 md:grid-cols-[2.5rem_minmax(0,1fr)]">
      <div className="hidden md:flex md:flex-col md:items-center">
        <div className="mt-3 h-3.5 w-3.5 rounded-full border-2 border-[var(--color-primary)] bg-[var(--color-card)]" />
        {index < total - 1 ? (
          <div className="mt-2 w-px flex-1 bg-[color-mix(in_oklch,var(--color-border)_72%,transparent)]" />
        ) : null}
      </div>

      <Card tone="subtle">
        <CardHeader className="gap-3">
          <div className="flex flex-col gap-3 lg:flex-row lg:items-center lg:justify-between">
            <div className="flex flex-wrap items-center gap-2">
              <Badge tone="primary" variant="outline">
                {message.kind}
              </Badge>
              <Badge variant="outline">{message.from_agent}</Badge>
              <span className="text-sm text-[var(--color-muted-foreground)]">to</span>
              <Badge variant="outline">{message.to_agent}</Badge>
            </div>
            <span className="text-xs text-[var(--color-muted-foreground)]">
              {formatDateTime(message.created_at)}
            </span>
          </div>
          <div className="space-y-2">
            <CardTitle>{message.summary}</CardTitle>
            <CardDescription className="text-sm leading-6">
              {message.message_id}
            </CardDescription>
          </div>
        </CardHeader>

        <CardContent className="grid gap-4">
          <p className="whitespace-pre-wrap text-sm leading-7 text-[var(--color-foreground)]">
            {message.body}
          </p>

          <div className="flex flex-wrap gap-2">
            {hasStructuredData(message.payload_json) ? (
              <JsonDialog
                description="Raw message payload as returned by the backend."
                label="Payload JSON"
                title={`Payload for ${message.message_id}`}
                value={message.payload_json}
              />
            ) : null}
            {message.artifacts.length > 0 ? (
              <Badge tone="warning" variant="outline">
                {pluralize(message.artifacts.length, 'artifact')}
              </Badge>
            ) : null}
          </div>

          {message.artifacts.length > 0 ? (
            <div className="grid gap-3">
              {message.artifacts.map((artifact) => (
                <div
                  className="flex flex-col gap-3 rounded-[1rem] border border-[color-mix(in_oklch,var(--color-border)_72%,transparent)] bg-[color-mix(in_oklch,var(--color-card)_90%,white_10%)] px-4 py-3 lg:flex-row lg:items-center lg:justify-between"
                  key={artifact.artifact_id}
                >
                  <div className="space-y-1">
                    <p className="text-sm font-medium text-[var(--color-foreground)]">{artifact.path}</p>
                    <p className="text-xs uppercase tracking-[0.16em] text-[var(--color-muted-foreground)]">
                      {artifact.kind}
                    </p>
                  </div>
                  {hasStructuredData(artifact.metadata_json) ? (
                    <JsonDialog
                      description="Artifact metadata emitted by the worker."
                      label="Artifact metadata"
                      title={`Artifact ${artifact.artifact_id}`}
                      value={artifact.metadata_json}
                    />
                  ) : null}
                </div>
              ))}
            </div>
          ) : null}
        </CardContent>
      </Card>
    </div>
  );
}

function QueryErrorState({
  title,
  description,
  onRetry,
}: {
  title: string;
  description: string;
  onRetry: () => void;
}) {
  return (
    <Alert icon={<SignalIcon />} variant="destructive">
      <AlertTitle>{title}</AlertTitle>
      <AlertDescription className="flex flex-col gap-3">
        <span>{description}</span>
        <div>
          <Button onClick={onRetry} size="sm" variant="subtle">
            Retry request
          </Button>
        </div>
      </AlertDescription>
    </Alert>
  );
}

function EmptyState({
  title,
  description,
}: {
  title: string;
  description: string;
}) {
  return (
    <Card tone="subtle">
      <CardContent className="flex min-h-64 flex-col items-center justify-center gap-4 p-10 text-center">
        <div className="flex h-16 w-16 items-center justify-center rounded-full border border-[color-mix(in_oklch,var(--color-border)_76%,transparent)] bg-[color-mix(in_oklch,var(--color-card)_84%,white_16%)] text-[var(--color-primary)]">
          <InboxIcon />
        </div>
        <div className="space-y-2">
          <h2 className="type-display text-[2rem] leading-none tracking-[-0.04em] text-[var(--color-foreground)]">
            {title}
          </h2>
          <p className="mx-auto max-w-2xl text-sm leading-7 text-[var(--color-muted-foreground)]">
            {description}
          </p>
        </div>
      </CardContent>
    </Card>
  );
}

function LoadingState({ count }: { count: number }) {
  return (
    <div className="grid gap-4 xl:grid-cols-2">
      {Array.from({ length: count }, (_, index) => (
        <Card key={index} tone="subtle">
          <CardContent className="grid gap-4 p-6">
            <div className="h-3 w-28 animate-pulse rounded-full bg-[color-mix(in_oklch,var(--color-border)_82%,white_18%)]" />
            <div className="h-12 w-3/4 animate-pulse rounded-[1rem] bg-[color-mix(in_oklch,var(--color-border)_72%,white_28%)]" />
            <div className="h-4 w-full animate-pulse rounded-full bg-[color-mix(in_oklch,var(--color-border)_70%,white_30%)]" />
            <div className="h-4 w-5/6 animate-pulse rounded-full bg-[color-mix(in_oklch,var(--color-border)_70%,white_30%)]" />
          </CardContent>
        </Card>
      ))}
    </div>
  );
}

function CompactStat({
  label,
  value,
}: {
  label: string;
  value: string;
}) {
  return (
    <div className="rounded-[1rem] border border-[color-mix(in_oklch,var(--color-border)_72%,transparent)] bg-[color-mix(in_oklch,var(--color-surface)_82%,white_18%)] px-4 py-3">
      <p className="text-[0.68rem] font-semibold uppercase tracking-[0.24em] text-[var(--color-muted-foreground)]">
        {label}
      </p>
      <p className="mt-2 break-all text-sm font-medium text-[var(--color-foreground)]">{value}</p>
    </div>
  );
}

function JsonDialog({
  label,
  title,
  description,
  value,
}: {
  label: string;
  title: string;
  description: string;
  value: unknown;
}) {
  const formatted = formatJson(value);
  const rows = Math.min(Math.max(formatted.split('\n').length, 8), 18);

  return (
    <Dialog>
      <DialogTrigger asChild>
        <Button size="sm" variant="ghost">
          {label}
        </Button>
      </DialogTrigger>
      <DialogContent size="lg">
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
          <DialogDescription>{description}</DialogDescription>
        </DialogHeader>
        <Textarea
          className="type-mono text-xs"
          readOnly
          rows={rows}
          value={formatted}
        />
      </DialogContent>
    </Dialog>
  );
}

function StatusBadge({ status }: { status: string }) {
  return (
    <Badge tone={badgeToneForStatus(status)} variant="subtle">
      {statusLabel(status)}
    </Badge>
  );
}

function PriorityBadge({ priority }: { priority: string }) {
  const normalized = priority.toLowerCase();
  const tone =
    normalized === 'high'
      ? 'warning'
      : normalized === 'urgent'
        ? 'destructive'
        : normalized === 'low'
          ? 'neutral'
          : 'primary';

  return (
    <Badge tone={tone} variant="outline">
      {priority}
    </Badge>
  );
}

function badgeToneForStatus(status: string): 'destructive' | 'neutral' | 'primary' | 'success' | 'warning' {
  switch (status) {
    case 'blocked':
      return 'warning';
    case 'done':
    case 'completed':
      return 'success';
    case 'failed':
    case 'cancelled':
      return 'destructive';
    case 'active':
    case 'in_progress':
      return 'primary';
    default:
      return 'neutral';
  }
}

function sortTaskCounts(counts: Record<string, number>) {
  const order = ['blocked', 'in_progress', 'active', 'ready', 'pending', 'done', 'completed', 'failed', 'cancelled'];
  const orderIndex = new Map(order.map((status, index) => [status, index] as const));

  return Object.entries(counts).sort((left, right) => {
    const leftOrder = orderIndex.get(left[0]) ?? Number.MAX_SAFE_INTEGER;
    const rightOrder = orderIndex.get(right[0]) ?? Number.MAX_SAFE_INTEGER;

    if (leftOrder !== rightOrder) {
      return leftOrder - rightOrder;
    }

    return left[0].localeCompare(right[0]);
  });
}

function groupTasks(tasks: Task[]) {
  const grouped = new Map<string, Task[]>();

  for (const task of tasks) {
    const bucket = grouped.get(task.status);
    if (bucket) {
      bucket.push(task);
      continue;
    }
    grouped.set(task.status, [task]);
  }

  return sortTaskCounts(
    Object.fromEntries(Array.from(grouped.entries(), ([status, items]) => [status, items.length])),
  ).map(([status]) => [status, grouped.get(status) ?? []] as const);
}

function matchesRun(item: RunListItem, filter: string) {
  if (!filter) {
    return true;
  }

  return [item.run.run_id, item.run.goal, item.run.summary].some((value) =>
    value.toLowerCase().includes(filter),
  );
}

function matchesTask(task: Task, filter: string) {
  if (!filter) {
    return true;
  }

  return [task.task_id, task.title, task.summary, task.default_to, task.priority].some(
    (value) => value?.toLowerCase().includes(filter) ?? false,
  );
}

function matchesBlockedItem(item: BlockedQueueItem, filter: string) {
  if (!filter) {
    return true;
  }

  return [
    item.run.run_id,
    item.task.task_id,
    item.task.title,
    item.task.summary,
    item.attempt.assigned_to,
    item.question.summary,
    item.question.body,
    item.question.from_agent,
    item.question.to_agent,
  ].some((value) => value.toLowerCase().includes(filter));
}

function SignalIcon() {
  return (
    <svg aria-hidden="true" className="h-5 w-5" fill="none" viewBox="0 0 24 24">
      <path
        d="M4 12h3l2-5 4 11 2-6h5"
        stroke="currentColor"
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth="1.8"
      />
    </svg>
  );
}

function InboxIcon() {
  return (
    <svg aria-hidden="true" className="h-6 w-6" fill="none" viewBox="0 0 24 24">
      <path
        d="M4 6.5h16v8.8l-2.4 2.7H6.4L4 15.3V6.5Z"
        stroke="currentColor"
        strokeLinejoin="round"
        strokeWidth="1.8"
      />
      <path
        d="M4.8 14.5h4.5l1.5 2h2.4l1.5-2h4.5"
        stroke="currentColor"
        strokeLinecap="round"
        strokeLinejoin="round"
        strokeWidth="1.8"
      />
    </svg>
  );
}
