import {
  ActionPanel,
  Action,
  Icon,
  Color,
  List,
  showToast,
  Toast,
  getPreferenceValues,
  showHUD,
} from "@raycast/api";
import { useEffect, useState, useMemo, useCallback } from "react";
import { execSync, spawn, exec } from "node:child_process";
import * as path from "node:path";
import * as os from "node:os";
import * as fs from "node:fs";
import * as https from "node:https";

interface Preferences {
  prodBucket?: string;
  devBucket?: string;
  repo?: string;
  branch?: string;
  githubToken?: string;
}

interface DownloadItem {
  id: string;
  env: "prod" | "dev";
  envLabel: "Production" | "Development";
  bucketHost: string;
  platform: "darwin" | "win32" | "linux";
  title: string;
  filename: string;
  version: string;
  url: string;
  sizeBytes?: number;
  releaseDate?: string;
  sha512?: string;
}

interface WorkflowRun {
  id: number;
  name: string;
  display_title: string;
  head_branch: string;
  head_sha: string;
  status: "queued" | "in_progress" | "completed" | "pending" | string;
  conclusion: "success" | "failure" | "cancelled" | "skipped" | "timed_out" | null | string;
  html_url: string;
  created_at: string;
  updated_at: string;
  run_attempt?: number;
  actor?: {
    login: string;
    avatar_url?: string;
  };
}

interface WorkflowJob {
  id: number;
  name: string;
  status: string;
  conclusion: string | null;
  started_at: string;
  completed_at: string | null;
  html_url: string;
  steps?: {
    name: string;
    status: string;
    conclusion: string | null;
    number: number;
  }[];
}

function getAuthToken(prefToken?: string): string | null {
  try {
    if (prefToken && prefToken.trim().length > 0) {
      return prefToken.trim();
    }
    if (process.env.GITHUB_TOKEN) return process.env.GITHUB_TOKEN;
    if (process.env.GH_TOKEN) return process.env.GH_TOKEN;

    const env = {
      ...process.env,
      PATH: `/opt/homebrew/bin:/usr/local/bin:/usr/bin:/bin:${process.env.PATH || ""}`,
    };

    const ghPaths = ["/opt/homebrew/bin/gh", "/usr/local/bin/gh", "gh"];
    for (const ghPath of ghPaths) {
      try {
        if (ghPath.startsWith("/") && !fs.existsSync(ghPath)) continue;
        const token = execSync(`${ghPath} auth token`, { env, encoding: "utf8", timeout: 3000 }).trim();
        if (token && token.length > 0) return token;
      } catch {
        // try next candidate
      }
    }
  } catch {
    // fallback
  }
  return null;
}

function formatBytes(bytes?: number): string {
  if (!bytes || bytes <= 0) return "";
  const mb = bytes / (1024 * 1024);
  return `${mb.toFixed(1)} MB`;
}

function formatTimeAgo(dateString?: string): string {
  if (!dateString) return "";
  const now = Date.now();
  const past = new Date(dateString).getTime();
  if (isNaN(past)) return "";
  const diffMs = Math.max(0, now - past);
  const diffSec = Math.floor(diffMs / 1000);
  if (diffSec < 60) return `${diffSec}s ago`;
  const diffMin = Math.floor(diffSec / 60);
  if (diffMin < 60) return `${diffMin}m ago`;
  const diffHours = Math.floor(diffMin / 60);
  if (diffHours < 24) return `${diffHours}h ${diffMin % 60}m ago`;
  const diffDays = Math.floor(diffHours / 24);
  return `${diffDays}d ago`;
}

function formatDuration(startStr?: string, endStr?: string | null): string {
  if (!startStr) return "";
  const start = new Date(startStr).getTime();
  const end = endStr ? new Date(endStr).getTime() : Date.now();
  if (isNaN(start) || isNaN(end)) return "";
  const diffMs = Math.max(0, end - start);
  const diffSec = Math.floor(diffMs / 1000);
  const min = Math.floor(diffSec / 60);
  const sec = diffSec % 60;
  if (min === 0) return `${sec}s`;
  if (min < 60) return `${min}m ${sec}s`;
  const hours = Math.floor(min / 60);
  return `${hours}h ${min % 60}m`;
}

function parseManifestYaml(yamlText: string): {
  version?: string;
  files: { url: string; size?: number; sha512?: string }[];
  releaseDate?: string;
} {
  const versionMatch = yamlText.match(/^version:\s*(.+)$/m);
  const version = versionMatch ? versionMatch[1].trim().replace(/^['"]|['"]$/g, "") : undefined;
  const releaseDateMatch = yamlText.match(/^releaseDate:\s*['"]?([^'"\n]+)['"]?/m);
  const releaseDate = releaseDateMatch ? releaseDateMatch[1].trim() : undefined;

  const files: { url: string; size?: number; sha512?: string }[] = [];
  const rawFileBlocks = yamlText.split(/\n\s*-\s*url:\s*/);

  if (rawFileBlocks.length > 1) {
    for (let i = 1; i < rawFileBlocks.length; i++) {
      const block = rawFileBlocks[i];
      const lines = block.split("\n");
      const url = lines[0]?.trim();
      if (!url) continue;

      let size: number | undefined;
      let sha512: string | undefined;

      for (let j = 1; j < lines.length; j++) {
        const line = lines[j];
        if (/^[a-zA-Z]/.test(line)) break;

        const sizeMatch = line.match(/^\s*size:\s*(\d+)/);
        if (sizeMatch) size = parseInt(sizeMatch[1], 10);
        const shaMatch = line.match(/^\s*sha512:\s*([^\s]+)/);
        if (shaMatch) sha512 = shaMatch[1];
      }
      files.push({ url, size, sha512 });
    }
  }

  if (files.length === 0) {
    const pathMatch = yamlText.match(/^path:\s*(.+)$/m);
    if (pathMatch) {
      const url = pathMatch[1].trim();
      const shaMatch = yamlText.match(/^sha512:\s*([^\s]+)/m);
      files.push({ url, sha512: shaMatch ? shaMatch[1] : undefined });
    }
  }

  return { version, files, releaseDate };
}

async function fetchManifest(url: string): Promise<string> {
  return new Promise((resolve, reject) => {
    const req = https.get(
      url,
      {
        headers: {
          "User-Agent": "Cachy-Strawberry-Extension",
          Accept: "text/yaml, text/plain, */*",
        },
      },
      (res) => {
        if (res.statusCode && res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
          fetchManifest(res.headers.location).then(resolve).catch(reject);
          return;
        }
        if (res.statusCode && res.statusCode >= 400) {
          return reject(new Error(`HTTP ${res.statusCode}`));
        }
        let data = "";
        res.on("data", (chunk) => (data += chunk));
        res.on("end", () => resolve(data));
      }
    );
    req.on("error", reject);
    req.setTimeout(8000, () => {
      req.destroy(new Error(`Timeout fetching ${url}`));
    });
  });
}

function getStatusIcon(status: string, conclusion: string | null) {
  if (status === "in_progress") {
    return { source: Icon.CircleProgress, tintColor: Color.Yellow };
  }
  if (status === "queued" || status === "pending") {
    return { source: Icon.Clock, tintColor: Color.Orange };
  }
  if (conclusion === "success") {
    return { source: Icon.CheckCircle, tintColor: Color.Green };
  }
  if (conclusion === "failure") {
    return { source: Icon.XMarkCircle, tintColor: Color.Red };
  }
  if (conclusion === "cancelled") {
    return { source: Icon.Stop, tintColor: Color.SecondaryText };
  }
  if (conclusion === "skipped") {
    return { source: Icon.MinusCircle, tintColor: Color.SecondaryText };
  }
  return { source: Icon.QuestionMark, tintColor: Color.SecondaryText };
}

function getStatusTag(status: string, conclusion: string | null) {
  if (status === "in_progress") {
    return { value: "In Progress", color: Color.Yellow };
  }
  if (status === "queued") {
    return { value: "Queued", color: Color.Orange };
  }
  if (status === "pending") {
    return { value: "Pending", color: Color.Orange };
  }
  if (conclusion === "success") {
    return { value: "Success", color: Color.Green };
  }
  if (conclusion === "failure") {
    return { value: "Failed", color: Color.Red };
  }
  if (conclusion === "cancelled") {
    return { value: "Cancelled", color: Color.SecondaryText };
  }
  return { value: status, color: Color.SecondaryText };
}

function getPlatformManifestName(platform: "darwin" | "win32" | "linux"): string {
  if (platform === "darwin") return "latest-mac.yml";
  if (platform === "win32") return "latest.yml";
  return "latest-linux.yml";
}

function formatDownloadTitle(filename: string, platform: "darwin" | "win32" | "linux"): string {
  const lower = filename.toLowerCase();
  if (lower.endsWith(".dmg")) return "macOS Universal (DMG)";
  if (lower.endsWith(".zip") && platform === "darwin") return "macOS Universal (ZIP)";
  if (lower.endsWith(".exe")) return "Windows Installer (EXE)";
  if (lower.endsWith(".appimage")) return "Linux AppImage";
  return filename;
}

export default function Command() {
  const preferences = getPreferenceValues<Preferences>();
  const prodBucket = preferences.prodBucket?.trim() || "strawberrybucket.com";
  const devBucket = preferences.devBucket?.trim() || "strawberrybucket.dev";
  const repo = preferences.repo?.trim() || "dendrite-systems/reflect-mono";
  const branch = preferences.branch?.trim() || "dev";
  const [token, setToken] = useState<string | null>(null);

  useEffect(() => {
    const resolvedToken = getAuthToken(preferences.githubToken);
    setToken(resolvedToken);
  }, [preferences.githubToken]);

  const [isLoading, setIsLoading] = useState(true);
  const [prodDownloads, setProdDownloads] = useState<DownloadItem[]>([]);
  const [devDownloads, setDevDownloads] = useState<DownloadItem[]>([]);
  const [runs, setRuns] = useState<WorkflowRun[]>([]);
  const [filter, setFilter] = useState<string>("all");

  const currentPlatform = useMemo<"darwin" | "win32" | "linux">(() => {
    const p = process.platform;
    return p === "darwin" || p === "win32" || p === "linux" ? p : "darwin";
  }, []);

  const loadData = useCallback(async () => {
    setIsLoading(true);
    const manifestFile = getPlatformManifestName(currentPlatform);

    // 1. Fetch Prod Manifest (strawberrybucket.com)
    try {
      const prodUrl = `https://${prodBucket}/${manifestFile}`;
      const prodText = await fetchManifest(prodUrl);
      const parsedProd = parseManifestYaml(prodText);
      const items: DownloadItem[] = parsedProd.files
        .filter((f) => !f.url.toLowerCase().endsWith(".zip"))
        .map((f) => ({
          id: `prod-${f.url}`,
          env: "prod",
          envLabel: "Production",
          bucketHost: prodBucket,
          platform: currentPlatform,
          title: formatDownloadTitle(f.url, currentPlatform),
          filename: f.url,
          version: parsedProd.version || "latest",
          url: `https://${prodBucket}/${f.url}`,
          sizeBytes: f.size,
          releaseDate: parsedProd.releaseDate,
          sha512: f.sha512,
        }));
      setProdDownloads(items);
    } catch (err) {
      console.error(`Failed to fetch prod manifest from ${prodBucket}`, err);
      setProdDownloads([]);
    }

    // 2. Fetch Dev Manifest (strawberrybucket.dev)
    try {
      const devUrl = `https://${devBucket}/${manifestFile}`;
      const devText = await fetchManifest(devUrl);
      const parsedDev = parseManifestYaml(devText);
      const items: DownloadItem[] = parsedDev.files
        .filter((f) => !f.url.toLowerCase().endsWith(".zip"))
        .map((f) => ({
          id: `dev-${f.url}`,
          env: "dev",
          envLabel: "Development",
          bucketHost: devBucket,
          platform: currentPlatform,
          title: formatDownloadTitle(f.url, currentPlatform),
          filename: f.url,
          version: parsedDev.version || "latest",
          url: `https://${devBucket}/${f.url}`,
          sizeBytes: f.size,
          releaseDate: parsedDev.releaseDate,
          sha512: f.sha512,
        }));
      setDevDownloads(items);
    } catch (err) {
      console.error(`Failed to fetch dev manifest from ${devBucket}`, err);
      setDevDownloads([]);
    }

    // 3. Fetch GitHub Actions CI Runs
    try {
      const currentToken = token ?? getAuthToken(preferences.githubToken);
      const headers: Record<string, string> = {
        Accept: "application/vnd.github.v3+json",
        "User-Agent": "Cachy-Strawberry-Extension",
      };
      if (currentToken) {
        headers["Authorization"] = `Bearer ${currentToken}`;
      }

      const res = await fetch(
        `https://api.github.com/repos/${repo}/actions/runs?branch=${branch}&per_page=30`,
        { headers }
      );

      if (res.ok) {
        const json = (await res.json()) as { workflow_runs: WorkflowRun[] };
        setRuns(json.workflow_runs || []);
      } else {
        const errText = await res.text();
        showToast({
          style: Toast.Style.Failure,
          title: "GitHub API Error",
          message: `HTTP ${res.status}: ${errText.slice(0, 100)}`,
        });
      }
    } catch (e: any) {
      console.error("Failed to fetch workflow runs", e);
    } finally {
      setIsLoading(false);
    }
  }, [prodBucket, devBucket, repo, branch, token, currentPlatform, preferences.githubToken]);

  useEffect(() => {
    loadData();
  }, [loadData]);

  const activeRuns = useMemo(
    () => runs.filter((r) => r.status === "in_progress" || r.status === "pending" || r.status === "queued"),
    [runs]
  );

  const completedRuns = useMemo(
    () => runs.filter((r) => r.status === "completed"),
    [runs]
  );

  const downloadToFolder = async (downloadUrl: string, filename: string) => {
    const toast = await showToast({
      style: Toast.Style.Animated,
      title: `Downloading ${filename}...`,
    });
    try {
      const destPath = path.join(os.homedir(), "Downloads", filename);
      const env = {
        ...process.env,
        PATH: ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", process.env.PATH]
          .filter(Boolean)
          .join(path.delimiter),
      };
      await new Promise<void>((resolve, reject) => {
        // Cachy intentionally terminates a view command's process group when
        // the view closes. Give the transfer its own process group and detach
        // its stdio so it can finish independently of the React command.
        const proc = spawn("curl", ["-fL", "-o", destPath, downloadUrl], {
          detached: true,
          env,
          stdio: "ignore",
        });
        proc.unref();
        proc.on("close", (code) => {
          if (code === 0) resolve();
          else reject(new Error(`curl exited with code ${code}`));
        });
        proc.on("error", reject);
      });

      toast.style = Toast.Style.Success;
      toast.title = "Downloaded to ~/Downloads";
      toast.message = filename;
      toast.primaryAction = {
        title: "Show in Finder",
        onAction: () => {
          exec(`open -R "${destPath}"`);
        },
      };
      showHUD(`Downloaded ${filename} to ~/Downloads`);
    } catch (err: any) {
      toast.style = Toast.Style.Failure;
      toast.title = "Download Failed";
      toast.message = err?.message || String(err);
    }
  };

  const shouldShowProdDownloads =
    (filter === "all" || filter === "prod" || filter === "downloads") && prodDownloads.length > 0;
  const shouldShowDevDownloads =
    (filter === "all" || filter === "dev" || filter === "downloads") && devDownloads.length > 0;
  const shouldShowActive = (filter === "all" || filter === "active") && activeRuns.length > 0;
  const shouldShowCompleted = filter === "all" || filter === "runs" || filter === "completed";

  const renderDownloadItem = (item: DownloadItem) => {
    const timeAgo = formatTimeAgo(item.releaseDate);
    const sizeStr = formatBytes(item.sizeBytes);
    const isProd = item.env === "prod";

    return (
      <List.Item
        key={item.id}
        icon={Icon.Download}
        title={item.title}
        subtitle={`${item.filename}${sizeStr ? ` • ${sizeStr}` : ""}`}
        accessories={[
          {
            tag: {
              value: `${isProd ? "Prod" : "Dev"} v${item.version}`,
              color: isProd ? Color.Green : Color.Purple,
            },
          },
          { text: timeAgo || "recently", icon: Icon.Clock },
        ]}
        actions={
          <ActionPanel>
            <ActionPanel.Section title="Download Actions">
              <Action
                title="Download to ~/Downloads"
                icon={Icon.Download}
                onAction={() => downloadToFolder(item.url, item.filename)}
              />
              <Action.OpenInBrowser url={item.url} title="Open Direct Download in Browser" />
              <Action.OpenInBrowser
                url={`https://${item.bucketHost}`}
                title={`Open ${item.bucketHost} in Browser`}
                icon={Icon.Globe}
              />
            </ActionPanel.Section>
            <ActionPanel.Section title="Copy Metadata">
              <Action.CopyToClipboard
                title="Copy Download URL"
                content={item.url}
                shortcut={{ modifiers: ["cmd"], key: "c" }}
              />
              <Action.CopyToClipboard
                title="Copy Version String"
                content={item.version}
                shortcut={{ modifiers: ["cmd", "shift"], key: "v" }}
              />
              {item.sha512 && (
                <Action.CopyToClipboard
                  title="Copy SHA512 Checksum"
                  content={item.sha512}
                  shortcut={{ modifiers: ["cmd", "shift"], key: "s" }}
                />
              )}
              {item.releaseDate && (
                <Action.CopyToClipboard
                  title="Copy Release Timestamp"
                  content={item.releaseDate}
                  shortcut={{ modifiers: ["cmd", "shift"], key: "t" }}
                />
              )}
            </ActionPanel.Section>
            <ActionPanel.Section title="General">
              <Action
                title="Refresh All"
                icon={Icon.ArrowClockwise}
                shortcut={{ modifiers: ["cmd"], key: "r" }}
                onAction={loadData}
              />
            </ActionPanel.Section>
          </ActionPanel>
        }
      />
    );
  };

  return (
    <List
      isLoading={isLoading}
      searchBarPlaceholder="Search versions, PRs, commits, downloads..."
      searchBarAccessory={
        <List.Dropdown
          tooltip="Filter View"
          value={filter}
          onChange={(newValue) => setFilter(newValue)}
        >
          <List.Dropdown.Item title="All (Prod, Dev & Runs)" value="all" />
          <List.Dropdown.Item title={`Production Only (${prodBucket})`} value="prod" />
          <List.Dropdown.Item title={`Development Only (${devBucket})`} value="dev" />
          <List.Dropdown.Item title="All Downloads (Prod & Dev)" value="downloads" />
          <List.Dropdown.Item title={`Active / Pending Builds (${activeRuns.length})`} value="active" />
          <List.Dropdown.Item title="Recent CI Runs" value="runs" />
        </List.Dropdown>
      }
    >
      {/* 1. Latest Production Releases Section */}
      {shouldShowProdDownloads && (
        <List.Section
          title={`Production Releases (${prodBucket})`}
          subtitle={prodDownloads[0] ? `v${prodDownloads[0].version}` : undefined}
        >
          {prodDownloads.map(renderDownloadItem)}
        </List.Section>
      )}

      {/* 2. Latest Development Builds Section */}
      {shouldShowDevDownloads && (
        <List.Section
          title={`Development Builds (${devBucket})`}
          subtitle={devDownloads[0] ? `v${devDownloads[0].version}` : undefined}
        >
          {devDownloads.map(renderDownloadItem)}
        </List.Section>
      )}

      {/* 3. Active & Pending Builds Section */}
      {shouldShowActive && (
        <List.Section title={`Active & Pending Builds (${activeRuns.length})`}>
          {activeRuns.map((run) => {
            const timeAgo = formatTimeAgo(run.created_at);
            const duration = formatDuration(run.created_at, null);
            const tag = getStatusTag(run.status, run.conclusion);
            const icon = getStatusIcon(run.status, run.conclusion);

            return (
              <List.Item
                key={run.id}
                icon={icon}
                title={run.display_title || run.name}
                subtitle={`${run.name} • ${run.head_sha.slice(0, 7)} by @${run.actor?.login || "unknown"}`}
                accessories={[
                  { tag },
                  { text: `Running for ${duration}` },
                  { text: `Started ${timeAgo}`, icon: Icon.Calendar },
                ]}
                actions={
                  <ActionPanel>
                    <ActionPanel.Section title="Run Actions">
                      <Action.Push
                        title="View Run Jobs & Progress"
                        icon={Icon.Eye}
                        target={<RunDetailView repo={repo} run={run} token={token} />}
                      />
                      <Action.OpenInBrowser url={run.html_url} title="Open Run on GitHub" />
                      <Action
                        title="Refresh Runs"
                        icon={Icon.ArrowClockwise}
                        shortcut={{ modifiers: ["cmd"], key: "r" }}
                        onAction={loadData}
                      />
                    </ActionPanel.Section>
                    <ActionPanel.Section title="Copy Info">
                      <Action.CopyToClipboard
                        title="Copy Run URL"
                        content={run.html_url}
                        shortcut={{ modifiers: ["cmd"], key: "c" }}
                      />
                      <Action.CopyToClipboard
                        title="Copy Commit SHA"
                        content={run.head_sha}
                        shortcut={{ modifiers: ["cmd", "shift"], key: "c" }}
                      />
                    </ActionPanel.Section>
                  </ActionPanel>
                }
              />
            );
          })}
        </List.Section>
      )}

      
      {/* 4. Recent CI Runs Section */}
      {shouldShowCompleted && (
        <List.Section title={`Recent CI Runs on ${branch} (${completedRuns.length})`}>
          {completedRuns.map((run) => {
            const timeAgo = formatTimeAgo(run.created_at);
            const duration = formatDuration(run.created_at, run.updated_at);
            const tag = getStatusTag(run.status, run.conclusion);
            const icon = getStatusIcon(run.status, run.conclusion);

            return (
              <List.Item
                key={run.id}
                icon={icon}
                title={run.display_title || run.name}
                subtitle={`${run.name} • ${run.head_sha.slice(0, 7)} by @${run.actor?.login || "unknown"}`}
                accessories={[
                  { tag },
                  { text: `Took ${duration}` },
                  { text: timeAgo, icon: Icon.Calendar },
                ]}
                actions={
                  <ActionPanel>
                    <ActionPanel.Section title="Run Details">
                      <Action.Push
                        title="View Jobs & Steps"
                        icon={Icon.Eye}
                        target={<RunDetailView repo={repo} run={run} token={token} />}
                      />
                      <Action.OpenInBrowser url={run.html_url} title="Open Run on GitHub" />
                    </ActionPanel.Section>
                    <ActionPanel.Section title="Copy & Share">
                      <Action.CopyToClipboard
                        title="Copy Run URL"
                        content={run.html_url}
                        shortcut={{ modifiers: ["cmd"], key: "c" }}
                      />
                      <Action.CopyToClipboard
                        title="Copy Commit SHA"
                        content={run.head_sha}
                        shortcut={{ modifiers: ["cmd", "shift"], key: "c" }}
                      />
                    </ActionPanel.Section>
                    <ActionPanel.Section title="Manage">
                      <Action
                        title="Refresh"
                        icon={Icon.ArrowClockwise}
                        shortcut={{ modifiers: ["cmd"], key: "r" }}
                        onAction={loadData}
                      />
                    </ActionPanel.Section>
                  </ActionPanel>
                }
              />
            );
          })}
        </List.Section>
      )}
    </List>
  );
}

function RunDetailView({ repo, run, token }: { repo: string; run: WorkflowRun; token: string | null }) {
  const [isLoading, setIsLoading] = useState(true);
  const [jobs, setJobs] = useState<WorkflowJob[]>([]);

  const fetchJobs = useCallback(async () => {
    setIsLoading(true);
    try {
      const headers: Record<string, string> = {
        Accept: "application/vnd.github.v3+json",
        "User-Agent": "Cachy-Strawberry-Extension",
      };
      if (token) headers["Authorization"] = `Bearer ${token}`;

      const res = await fetch(`https://api.github.com/repos/${repo}/actions/runs/${run.id}/jobs`, { headers });
      if (res.ok) {
        const json = (await res.json()) as { jobs: WorkflowJob[] };
        setJobs(json.jobs || []);
      }
    } catch (e) {
      console.error(e);
    } finally {
      setIsLoading(false);
    }
  }, [repo, run.id, token]);

  useEffect(() => {
    fetchJobs();
  }, [fetchJobs]);

  const duration = formatDuration(run.created_at, run.status === "completed" ? run.updated_at : null);
  const timeAgo = formatTimeAgo(run.created_at);

  return (
    <List
      isLoading={isLoading}
      navigationTitle={`${run.name} #${run.id}`}
      searchBarPlaceholder="Search job names, steps..."
    >
      <List.Section title={`Overview: ${run.display_title}`}>
        <List.Item
          icon={getStatusIcon(run.status, run.conclusion)}
          title={`Status: ${run.conclusion || run.status}`}
          subtitle={`Triggered ${timeAgo} • Total duration: ${duration}`}
          accessories={[
            { text: `Branch: ${run.head_branch}` },
            { text: `Commit: ${run.head_sha.slice(0, 7)}` },
          ]}
          actions={
            <ActionPanel>
              <Action.OpenInBrowser url={run.html_url} title="Open Run on GitHub" />
              <Action.CopyToClipboard title="Copy Run URL" content={run.html_url} />
            </ActionPanel>
          }
        />
      </List.Section>

      <List.Section title={`Workflow Jobs (${jobs.length})`}>
        {jobs.map((job) => {
          const jobDuration = formatDuration(job.started_at, job.completed_at);
          const jobIcon = getStatusIcon(job.status, job.conclusion);
          const jobTag = getStatusTag(job.status, job.conclusion);

          return (
            <List.Item
              key={job.id}
              icon={jobIcon}
              title={job.name}
              subtitle={job.steps ? `${job.steps.length} steps` : undefined}
              accessories={[
                { tag: jobTag },
                { text: jobDuration ? `Took ${jobDuration}` : "Running..." },
              ]}
              actions={
                <ActionPanel>
                  <Action.OpenInBrowser url={job.html_url} title="Open Job on GitHub" />
                  <Action.OpenInBrowser url={run.html_url} title="Open Full Run on GitHub" />
                  <Action
                    title="Refresh Jobs"
                    icon={Icon.ArrowClockwise}
                    shortcut={{ modifiers: ["cmd"], key: "r" }}
                    onAction={fetchJobs}
                  />
                  <Action.CopyToClipboard title="Copy Job URL" content={job.html_url} />
                </ActionPanel>
              }
            />
          );
        })}
      </List.Section>
    </List>
  );
}
