"use client";

import * as React from "react";
import { useParams } from "next/navigation";
import {
  Activity,
  ChevronDown,
  ChevronRight,
  Loader2,
  PlayCircle,
} from "lucide-react";

import { api } from "@/lib/trpc";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import { cn } from "@/lib/utils";

/**
 * Read-side dashboard for `agent_runs`. Mirrors the audit page's visual
 * language but is open to all workspace members — runs aren't as
 * sensitive as the audit log and the value is mostly debugging the
 * orchestration layer once the MCP write paths land.
 *
 * The "Recent runs" section pages with keyset pagination on
 * `started_at`. Click any row to expand and see the row's `notes` and
 * `error` text — kept collapsed by default because most runs are
 * uneventful and the table needs to stay scannable.
 */

const FILTER_OPTIONS = ["all", "succeeded", "failed", "cancelled", "stalled", "open"] as const;
type FilterOption = (typeof FILTER_OPTIONS)[number];

const FILTER_LABEL: Record<FilterOption, string> = {
  all: "All",
  succeeded: "Succeeded",
  failed: "Failed",
  cancelled: "Cancelled",
  stalled: "Stalled",
  open: "Open",
};

const OUTCOME_CHIP: Record<string, string> = {
  succeeded:
    "bg-emerald-500/15 text-emerald-700 dark:text-emerald-300 ring-1 ring-emerald-500/20",
  failed:
    "bg-red-500/15 text-red-700 dark:text-red-300 ring-1 ring-red-500/20",
  cancelled:
    "bg-amber-500/15 text-amber-700 dark:text-amber-300 ring-1 ring-amber-500/20",
  stalled:
    "bg-orange-500/15 text-orange-700 dark:text-orange-300 ring-1 ring-orange-500/20",
  open: "bg-sky-500/15 text-sky-700 dark:text-sky-300 ring-1 ring-sky-500/20",
};

function formatTimestamp(when: Date | string): string {
  const d = when instanceof Date ? when : new Date(when);
  return d.toLocaleString(undefined, {
    month: "short",
    day: "numeric",
    hour: "2-digit",
    minute: "2-digit",
  });
}

/**
 * Format a duration in milliseconds as a compact string. Returns "—"
 * for in-flight runs (no `finishedAt`). Below a minute we show seconds
 * with a single decimal so quick MCP calls don't all look like "0s".
 */
export function formatDuration(
  startedAt: Date | string,
  finishedAt: Date | string | null,
): string {
  if (!finishedAt) return "—";
  const start = startedAt instanceof Date ? startedAt : new Date(startedAt);
  const end = finishedAt instanceof Date ? finishedAt : new Date(finishedAt);
  const ms = end.getTime() - start.getTime();
  if (!Number.isFinite(ms) || ms < 0) return "—";
  const seconds = ms / 1000;
  if (seconds < 60) return `${seconds.toFixed(seconds < 10 ? 1 : 0)}s`;
  const minutes = seconds / 60;
  if (minutes < 60) return `${Math.round(minutes)}m`;
  const hours = minutes / 60;
  return `${hours.toFixed(hours < 10 ? 1 : 0)}h`;
}

function formatTokens(n: number | null): string {
  if (n === null || n === undefined) return "—";
  if (n < 1000) return String(n);
  if (n < 1_000_000) return `${(n / 1000).toFixed(n < 10_000 ? 1 : 0)}k`;
  return `${(n / 1_000_000).toFixed(1)}M`;
}

function describeOutcome(
  outcome: string | null,
  finishedAt: Date | string | null,
): { label: string; key: keyof typeof OUTCOME_CHIP } {
  if (!finishedAt) return { label: "open", key: "open" };
  const key = outcome && outcome in OUTCOME_CHIP ? outcome : "open";
  return { label: outcome ?? "open", key: key as keyof typeof OUTCOME_CHIP };
}

export default function RunsPage() {
  const params = useParams();
  const workspaceSlug = params?.workspaceSlug as string | undefined;

  const [filter, setFilter] = React.useState<FilterOption>("all");
  const [cursor, setCursor] = React.useState<string | undefined>(undefined);
  const [expanded, setExpanded] = React.useState<string | null>(null);

  // Reset pagination + expansion state when the user switches filters so
  // we never end up showing a cursor that was generated for a different
  // outcome subset.
  const onFilterChange = React.useCallback((next: FilterOption) => {
    setFilter(next);
    setCursor(undefined);
    setExpanded(null);
  }, []);

  const filterArg = filter === "all" ? undefined : filter;

  const summaryQuery = api.runs.summary.useQuery(
    { workspace: workspaceSlug ?? "" },
    { enabled: Boolean(workspaceSlug) },
  );

  const runsQuery = api.runs.listRecent.useQuery(
    {
      workspace: workspaceSlug ?? "",
      limit: 25,
      cursorStartedAt: cursor,
      outcome: filterArg,
    },
    { enabled: Boolean(workspaceSlug) },
  );

  return (
    <div className="mx-auto max-w-5xl px-8 py-10">
      <div className="mb-8 flex items-center gap-3">
        <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10">
          <Activity className="size-5 text-primary" />
        </div>
        <div>
          <h1 className="text-xl font-semibold">Agent runs</h1>
          <p className="text-xs text-muted-foreground">
            Every agent session against a task. Read-only — write paths land
            with the orchestrator MCP tools.
          </p>
        </div>
      </div>

      {/* Summary card */}
      <SummaryCard
        loading={summaryQuery.isLoading}
        data={summaryQuery.data}
        error={summaryQuery.error?.message}
      />

      {/* Outcome filter pills */}
      <div className="mt-6 flex flex-wrap gap-1.5">
        {FILTER_OPTIONS.map((option) => (
          <button
            key={option}
            type="button"
            onClick={() => onFilterChange(option)}
            className={cn(
              "rounded-full px-3 py-1 text-xs font-medium transition-colors",
              filter === option
                ? "bg-primary text-primary-foreground"
                : "bg-muted text-muted-foreground hover:bg-muted/80",
            )}
          >
            {FILTER_LABEL[option]}
          </button>
        ))}
      </div>

      {/* Recent runs table */}
      <div className="mt-4">
        {runsQuery.isLoading ? (
          <div className="space-y-2">
            {Array.from({ length: 6 }).map((_, i) => (
              <Skeleton key={i} className="h-12 w-full" />
            ))}
          </div>
        ) : runsQuery.error ? (
          <div className="rounded-lg border border-destructive/40 bg-destructive/5 px-4 py-3 text-sm text-destructive">
            Couldn&apos;t load runs: {runsQuery.error.message}
          </div>
        ) : !runsQuery.data || runsQuery.data.rows.length === 0 ? (
          <EmptyState filter={filter} />
        ) : (
          <>
            <div className="overflow-hidden rounded-lg border">
              <table className="w-full text-sm">
                <thead className="bg-muted/40 text-xs uppercase tracking-wide text-muted-foreground">
                  <tr>
                    <th className="w-8 px-2 py-2" aria-label="Expand" />
                    <th className="px-4 py-2 text-left font-medium">Task</th>
                    <th className="px-4 py-2 text-left font-medium">Started</th>
                    <th className="px-4 py-2 text-left font-medium">Duration</th>
                    <th className="px-4 py-2 text-left font-medium">Actor</th>
                    <th className="px-4 py-2 text-left font-medium">Outcome</th>
                    <th className="px-4 py-2 text-right font-medium">Tokens</th>
                  </tr>
                </thead>
                <tbody className="divide-y">
                  {runsQuery.data.rows.map((row) => {
                    const { label, key } = describeOutcome(row.outcome, row.finishedAt);
                    const isOpen = expanded === row.id;
                    const hasDetail = Boolean(row.notes || row.error);
                    return (
                      <React.Fragment key={row.id}>
                        <tr
                          className={cn(
                            "transition-colors",
                            hasDetail
                              ? "cursor-pointer hover:bg-muted/30"
                              : "hover:bg-muted/20",
                          )}
                          onClick={() => {
                            if (hasDetail) {
                              setExpanded(isOpen ? null : row.id);
                            }
                          }}
                        >
                          <td className="px-2 py-2 align-middle">
                            {hasDetail ? (
                              isOpen ? (
                                <ChevronDown className="size-3.5 text-muted-foreground" />
                              ) : (
                                <ChevronRight className="size-3.5 text-muted-foreground" />
                              )
                            ) : null}
                          </td>
                          <td className="max-w-[24ch] truncate px-4 py-2 font-medium">
                            {row.taskTitle ?? (
                              <span className="font-mono text-xs text-muted-foreground">
                                {row.backlogItemId.slice(0, 8)}
                              </span>
                            )}
                          </td>
                          <td className="whitespace-nowrap px-4 py-2 text-xs tabular-nums text-muted-foreground">
                            {formatTimestamp(row.startedAt)}
                          </td>
                          <td className="whitespace-nowrap px-4 py-2 text-xs tabular-nums">
                            {formatDuration(row.startedAt, row.finishedAt)}
                          </td>
                          <td className="px-4 py-2 text-xs">
                            {row.actorUserId ? (
                              <span>
                                {row.actorName ?? row.actorEmail ?? row.actorUserId.slice(0, 8)}
                              </span>
                            ) : (
                              <span className="italic text-muted-foreground">—</span>
                            )}
                          </td>
                          <td className="px-4 py-2">
                            <span
                              className={cn(
                                "inline-flex items-center rounded-full px-2 py-0.5 text-xs font-medium",
                                OUTCOME_CHIP[key],
                              )}
                            >
                              {label}
                            </span>
                          </td>
                          <td className="whitespace-nowrap px-4 py-2 text-right text-xs tabular-nums">
                            {formatTokens(row.tokensTotal)}
                          </td>
                        </tr>
                        {isOpen && hasDetail ? (
                          <tr>
                            <td />
                            <td colSpan={6} className="bg-muted/20 px-4 py-3 text-xs">
                              {row.notes ? (
                                <div className="mb-2">
                                  <div className="mb-1 text-[10px] uppercase tracking-wide text-muted-foreground">
                                    Notes
                                  </div>
                                  <p className="whitespace-pre-wrap">{row.notes}</p>
                                </div>
                              ) : null}
                              {row.error ? (
                                <div>
                                  <div className="mb-1 text-[10px] uppercase tracking-wide text-muted-foreground">
                                    Error
                                  </div>
                                  <pre className="whitespace-pre-wrap rounded bg-background/60 px-2 py-1 font-mono text-[11px] text-destructive">
                                    {row.error}
                                  </pre>
                                </div>
                              ) : null}
                            </td>
                          </tr>
                        ) : null}
                      </React.Fragment>
                    );
                  })}
                </tbody>
              </table>
            </div>

            {runsQuery.data.nextCursor ? (
              <div className="mt-4 flex justify-center">
                <Button
                  variant="outline"
                  size="sm"
                  onClick={() => setCursor(runsQuery.data.nextCursor ?? undefined)}
                  disabled={runsQuery.isFetching}
                >
                  {runsQuery.isFetching ? (
                    <Loader2 className="size-3 animate-spin" />
                  ) : (
                    "Load older"
                  )}
                </Button>
              </div>
            ) : null}
          </>
        )}
      </div>
    </div>
  );
}

function EmptyState({ filter }: { filter: FilterOption }) {
  return (
    <div className="flex flex-col items-center gap-3 rounded-lg border bg-muted/40 px-6 py-12 text-center">
      <PlayCircle className="size-6 text-muted-foreground" />
      <p className="text-sm font-medium">
        {filter === "all" ? "No runs yet" : `No ${FILTER_LABEL[filter].toLowerCase()} runs`}
      </p>
      <p className="max-w-sm text-xs text-muted-foreground">
        Once an agent session runs against a task — via the orchestrator
        or a manually-inserted row — it will appear here.
      </p>
    </div>
  );
}

type SummaryData = {
  byOutcome: Record<"succeeded" | "failed" | "cancelled" | "stalled" | "open", number>;
  tokensTotal: number;
};

function SummaryCard({
  loading,
  data,
  error,
}: {
  loading: boolean;
  data: SummaryData | undefined;
  error: string | undefined;
}) {
  if (loading) {
    return (
      <div className="grid grid-cols-2 gap-3 sm:grid-cols-6">
        {Array.from({ length: 6 }).map((_, i) => (
          <Skeleton key={i} className="h-20 w-full" />
        ))}
      </div>
    );
  }

  if (error) {
    return (
      <div className="rounded-lg border border-destructive/40 bg-destructive/5 px-4 py-3 text-sm text-destructive">
        Couldn&apos;t load summary: {error}
      </div>
    );
  }

  if (!data) return null;

  const cells: Array<{ label: string; value: string; key: keyof typeof OUTCOME_CHIP | "tokens" }> = [
    { label: "Succeeded", value: String(data.byOutcome.succeeded), key: "succeeded" },
    { label: "Failed", value: String(data.byOutcome.failed), key: "failed" },
    { label: "Cancelled", value: String(data.byOutcome.cancelled), key: "cancelled" },
    { label: "Stalled", value: String(data.byOutcome.stalled), key: "stalled" },
    { label: "Open", value: String(data.byOutcome.open), key: "open" },
    { label: "Tokens (7d)", value: formatTokens(data.tokensTotal), key: "tokens" },
  ];

  return (
    <div className="grid grid-cols-2 gap-3 sm:grid-cols-6">
      {cells.map((cell) => (
        <div
          key={cell.label}
          className="rounded-lg border bg-card px-3 py-3"
        >
          <div className="text-[10px] uppercase tracking-wide text-muted-foreground">
            {cell.label}
          </div>
          <div className="mt-1 text-2xl font-semibold tabular-nums">{cell.value}</div>
        </div>
      ))}
    </div>
  );
}
