"use client";

import { useState, useEffect } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import {
  Settings,
  Cpu,
  RefreshCw,
  CheckCircle,
  XCircle,
  Play,
  Users,
  Trash2,
  ShieldCheck,
  ShieldOff,
  BarChart3,
  Bell,
} from "lucide-react";
import Link from "next/link";
import { settingsAPI, adminAPI, type AdminUser, type LLMModel, type ApiHealthResult } from "@/lib/api";
import { useAuthStore } from "@/stores/authStore";

const LLM_PROVIDERS = [
  { value: "openai", label: "OpenAI", hint: "Requires OPENAI_API_KEY in .env" },
  { value: "anthropic", label: "Anthropic (Claude)", hint: "Requires ANTHROPIC_API_KEY in .env" },
  { value: "gemini", label: "Google Gemini", hint: "Requires GEMINI_API_KEY in .env" },
  { value: "ollama", label: "Ollama (Local)", hint: "Requires Ollama running on host" },
];


export default function SettingsPage() {
  const qc = useQueryClient();
  const currentUser = useAuthStore((s) => s.user);

  const { data: settings, isLoading: settingsLoading } = useQuery({
    queryKey: ["settings"],
    queryFn: () => settingsAPI.get(),
  });

  const { data: stats } = useQuery({
    queryKey: ["admin-stats"],
    queryFn: () => adminAPI.getStats(),
    enabled: !!currentUser?.is_admin,
    refetchInterval: 30_000,
  });

  const [healthTesting, setHealthTesting] = useState(false);
  const [healthData, setHealthData] = useState<Record<string, ApiHealthResult> | null>(null);
  const testApiHealth = async () => {
    setHealthTesting(true);
    try {
      const result = await adminAPI.getApiHealth();
      setHealthData(result as unknown as Record<string, ApiHealthResult>);
    } finally {
      setHealthTesting(false);
    }
  };

  const { data: users, isLoading: usersLoading } = useQuery({
    queryKey: ["admin-users"],
    queryFn: () => adminAPI.listUsers(),
    enabled: !!currentUser?.is_admin,
  });

  const updateSetting = useMutation({
    mutationFn: ({ key, value }: { key: string; value: string }) => settingsAPI.update(key, value),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["settings"] }),
  });

  const deleteUser = useMutation({
    mutationFn: (id: number) => adminAPI.deleteUser(id),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["admin-users"] }),
  });

  const toggleAdmin = useMutation({
    mutationFn: (id: number) => adminAPI.toggleAdmin(id),
    onSuccess: () => qc.invalidateQueries({ queryKey: ["admin-users"] }),
  });

  // Live model list from provider API
  const { data: modelsData, isFetching: modelsFetching, refetch: refetchModels } = useQuery({
    queryKey: ["llm-models", settings?.llm_provider],
    queryFn: () => settingsAPI.listModels(settings!.llm_provider),
    enabled: !!currentUser?.is_admin && !!settings?.llm_provider,
    staleTime: 5 * 60 * 1000,
    retry: false,
  });
  const liveModels: LLMModel[] = modelsData?.models ?? [];
  const modelsError: string | undefined = modelsData?.error;

  // Model picker state
  const [showCustomModel, setShowCustomModel] = useState(false);
  const [customModel, setCustomModel] = useState("");
  useEffect(() => {
    if (!settings || modelsFetching) return;
    const inList = liveModels.some((m) => m.id === settings.llm_model);
    if (!inList && settings.llm_model) {
      setShowCustomModel(true);
      setCustomModel(settings.llm_model);
    } else {
      setShowCustomModel(false);
      setCustomModel("");
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [settings?.llm_provider, settings?.llm_model, modelsFetching]);

  const [testResult, setTestResult] = useState<{
    status: string;
    detail?: string;
    reply?: string;
    provider?: string;
    model?: string;
  } | null>(null);
  const [testing, setTesting] = useState(false);
  const [taskIds, setTaskIds] = useState<Record<string, string>>({});
  const [taskStatuses, setTaskStatuses] = useState<Record<string, "running" | "done" | "error">>({});
  const [confirmDelete, setConfirmDelete] = useState<number | null>(null);

  const testLLM = async () => {
    setTesting(true);
    setTestResult(null);
    try {
      const result = await settingsAPI.testLLM();
      setTestResult(result);
    } catch (e: unknown) {
      setTestResult({ status: "error", detail: e instanceof Error ? e.message : String(e) });
    } finally {
      setTesting(false);
    }
  };

  const pollTaskStatus = async (name: string, taskId: string) => {
    for (let i = 0; i < 60; i++) {
      await new Promise((r) => setTimeout(r, 5000));
      try {
        const data = await adminAPI.getTaskStatus(taskId);
        if (["SUCCESS", "FAILURE", "REVOKED"].includes(data.status)) {
          setTaskStatuses((prev) => ({ ...prev, [name]: data.status === "SUCCESS" ? "done" : "error" }));
          qc.invalidateQueries({ queryKey: ["admin-stats"] });
          return;
        }
      } catch { /* ignore polling errors */ }
    }
    setTaskStatuses((prev) => ({ ...prev, [name]: "error" }));
  };

  const trigger = async (name: string, fn: () => Promise<{ task_id: string }>) => {
    const result = await fn();
    setTaskIds((prev) => ({ ...prev, [name]: result.task_id }));
    setTaskStatuses((prev) => ({ ...prev, [name]: "running" }));
    pollTaskStatus(name, result.task_id);
  };

  if (settingsLoading) return <div className="text-center py-20 text-muted-foreground">Loading...</div>;

  if (!currentUser?.is_admin) {
    return <div className="text-center py-20 text-muted-foreground">Admin access required.</div>;
  }

  const pct = stats && stats.total_bills > 0
    ? Math.round((stats.briefs_generated / stats.total_bills) * 100)
    : 0;

  return (
    <div className="space-y-8 max-w-2xl">
      <div>
        <h1 className="text-2xl font-bold flex items-center gap-2">
          <Settings className="w-5 h-5" /> Admin
        </h1>
        <p className="text-muted-foreground text-sm mt-1">Manage users, LLM provider, and system settings</p>
      </div>

      {/* Notifications link */}
      <Link
        href="/notifications"
        className="flex items-center justify-between bg-card border border-border rounded-lg p-4 hover:bg-accent transition-colors group"
      >
        <div className="flex items-center gap-3">
          <Bell className="w-4 h-4 text-muted-foreground group-hover:text-foreground" />
          <div>
            <div className="text-sm font-medium">Notification Settings</div>
            <div className="text-xs text-muted-foreground">Configure ntfy push alerts and RSS feed per user</div>
          </div>
        </div>
        <span className="text-xs text-muted-foreground group-hover:text-foreground">→</span>
      </Link>

      {/* Analysis Status */}
      <section className="bg-card border border-border rounded-lg p-6 space-y-4">
        <h2 className="font-semibold flex items-center gap-2">
          <BarChart3 className="w-4 h-4" /> Bill Pipeline
          <span className="text-xs text-muted-foreground font-normal ml-auto">refreshes every 30s</span>
        </h2>
        {stats ? (
          <>
            {/* Progress bar */}
            <div className="space-y-1">
              <div className="flex justify-between text-xs text-muted-foreground">
                <span>{stats.briefs_generated.toLocaleString()} analyzed ({stats.full_briefs} full · {stats.amendment_briefs} amendments)</span>
                <span>{pct}% of {stats.total_bills.toLocaleString()} bills</span>
              </div>
              <div className="h-2 bg-muted rounded-full overflow-hidden">
                <div
                  className="h-full bg-green-500 rounded-full transition-all duration-500"
                  style={{ width: `${pct}%` }}
                />
              </div>
            </div>

            {/* Pipeline breakdown table */}
            <div className="divide-y divide-border text-sm">
              {[
                { label: "Total bills tracked", value: stats.total_bills, color: "text-foreground", icon: "📋" },
                { label: "Text published on Congress.gov", value: stats.docs_fetched, color: "text-blue-600 dark:text-blue-400", icon: "📄" },
                { label: "No text published yet", value: stats.no_text_bills, color: "text-muted-foreground", icon: "⏳", note: "Normal — bill text appears after committee markup" },
                { label: "AI briefs generated", value: stats.briefs_generated, color: "text-green-600 dark:text-green-400", icon: "✅" },
                { label: "Pending LLM analysis", value: stats.pending_llm, color: stats.pending_llm > 0 ? "text-amber-600 dark:text-amber-400" : "text-muted-foreground", icon: "🔄", action: stats.pending_llm > 0 ? "Resume Analysis" : undefined },
                { label: "Briefs missing citations", value: stats.uncited_briefs, color: stats.uncited_briefs > 0 ? "text-amber-600 dark:text-amber-400" : "text-muted-foreground", icon: "⚠️", action: stats.uncited_briefs > 0 ? "Backfill Citations" : undefined },
              ].map(({ label, value, color, icon, note, action }) => (
                <div key={label} className="flex items-center justify-between py-2.5 gap-3">
                  <div className="flex items-center gap-2 min-w-0">
                    <span className="text-base leading-none shrink-0">{icon}</span>
                    <div>
                      <span className="text-sm">{label}</span>
                      {note && <p className="text-xs text-muted-foreground mt-0.5">{note}</p>}
                    </div>
                  </div>
                  <div className="flex items-center gap-3 shrink-0">
                    <span className={`font-semibold tabular-nums ${color}`}>{value.toLocaleString()}</span>
                    {action && (
                      <span className="text-xs text-muted-foreground">→ run {action}</span>
                    )}
                  </div>
                </div>
              ))}
            </div>
          </>
        ) : (
          <p className="text-sm text-muted-foreground">Loading stats...</p>
        )}
      </section>

      {/* User Management */}
      <section className="bg-card border border-border rounded-lg p-6 space-y-4">
        <h2 className="font-semibold flex items-center gap-2">
          <Users className="w-4 h-4" /> Users
        </h2>
        {usersLoading ? (
          <p className="text-sm text-muted-foreground">Loading users...</p>
        ) : (
          <div className="divide-y divide-border">
            {(users ?? []).map((u: AdminUser) => (
              <div key={u.id} className="flex items-center justify-between py-3 gap-4">
                <div className="min-w-0">
                  <div className="flex items-center gap-2">
                    <span className="text-sm font-medium truncate">{u.email}</span>
                    {u.is_admin && (
                      <span className="text-xs bg-primary/10 text-primary px-1.5 py-0.5 rounded font-medium">
                        admin
                      </span>
                    )}
                    {u.id === currentUser.id && (
                      <span className="text-xs text-muted-foreground">(you)</span>
                    )}
                  </div>
                  <div className="text-xs text-muted-foreground mt-0.5">
                    {u.follow_count} follow{u.follow_count !== 1 ? "s" : ""} ·{" "}
                    joined {new Date(u.created_at).toLocaleDateString()}
                  </div>
                </div>
                {u.id !== currentUser.id && (
                  <div className="flex items-center gap-2 shrink-0">
                    <button
                      onClick={() => toggleAdmin.mutate(u.id)}
                      disabled={toggleAdmin.isPending}
                      title={u.is_admin ? "Remove admin" : "Make admin"}
                      className="p-1.5 rounded-md text-muted-foreground hover:text-foreground hover:bg-accent transition-colors"
                    >
                      {u.is_admin ? <ShieldOff className="w-4 h-4" /> : <ShieldCheck className="w-4 h-4" />}
                    </button>
                    {confirmDelete === u.id ? (
                      <div className="flex items-center gap-1">
                        <button
                          onClick={() => { deleteUser.mutate(u.id); setConfirmDelete(null); }}
                          className="text-xs px-2 py-1 bg-destructive text-destructive-foreground rounded hover:bg-destructive/90"
                        >
                          Confirm
                        </button>
                        <button
                          onClick={() => setConfirmDelete(null)}
                          className="text-xs px-2 py-1 bg-muted rounded hover:bg-accent"
                        >
                          Cancel
                        </button>
                      </div>
                    ) : (
                      <button
                        onClick={() => setConfirmDelete(u.id)}
                        title="Delete user"
                        className="p-1.5 rounded-md text-muted-foreground hover:text-destructive hover:bg-accent transition-colors"
                      >
                        <Trash2 className="w-4 h-4" />
                      </button>
                    )}
                  </div>
                )}
              </div>
            ))}
          </div>
        )}
      </section>

      {/* LLM Provider */}
      <section className="bg-card border border-border rounded-lg p-6 space-y-4">
        <h2 className="font-semibold flex items-center gap-2">
          <Cpu className="w-4 h-4" /> LLM Provider
        </h2>
        <div className="space-y-2">
          {LLM_PROVIDERS.map(({ value, label, hint }) => (
            <label key={value} className="flex items-start gap-3 cursor-pointer">
              <input
                type="radio"
                name="provider"
                value={value}
                checked={settings?.llm_provider === value}
                onChange={() => {
                  updateSetting.mutate({ key: "llm_provider", value });
                  setShowCustomModel(false);
                  setCustomModel("");
                }}
                className="mt-0.5"
              />
              <div>
                <div className="text-sm font-medium">{label}</div>
                <div className="text-xs text-muted-foreground">{hint}</div>
              </div>
            </label>
          ))}
        </div>

        {/* Model picker — live from provider API */}
        <div className="space-y-2 pt-3 border-t border-border">
          <div className="flex items-center justify-between">
            <label className="text-xs font-medium text-muted-foreground uppercase tracking-wide">Model</label>
            {modelsFetching && <span className="text-xs text-muted-foreground">Loading models…</span>}
            {modelsError && !modelsFetching && (
              <span className="text-xs text-amber-600 dark:text-amber-400">{modelsError}</span>
            )}
            {!modelsFetching && liveModels.length > 0 && (
              <button onClick={() => refetchModels()} className="text-xs text-muted-foreground hover:text-foreground transition-colors">
                Refresh
              </button>
            )}
          </div>

          {liveModels.length > 0 ? (
            <select
              value={showCustomModel ? "__custom__" : (settings?.llm_model ?? "")}
              onChange={(e) => {
                if (e.target.value === "__custom__") {
                  setShowCustomModel(true);
                  setCustomModel(settings?.llm_model ?? "");
                } else {
                  setShowCustomModel(false);
                  setCustomModel("");
                  updateSetting.mutate({ key: "llm_model", value: e.target.value });
                }
              }}
              className="w-full px-3 py-1.5 text-sm bg-background border border-border rounded-md"
            >
              {liveModels.map((m) => (
                <option key={m.id} value={m.id}>{m.name !== m.id ? `${m.name} (${m.id})` : m.id}</option>
              ))}
              <option value="__custom__">Custom model name…</option>
            </select>
          ) : (
            !modelsFetching && (
              <p className="text-xs text-muted-foreground">
                {modelsError ? "Could not fetch models — enter a model name manually below." : "No models found."}
              </p>
            )
          )}

          {(showCustomModel || (liveModels.length === 0 && !modelsFetching)) && (
            <div className="flex gap-2">
              <input
                type="text"
                placeholder="e.g. gpt-4o or gemini-2.0-flash"
                value={customModel}
                onChange={(e) => setCustomModel(e.target.value)}
                className="flex-1 px-3 py-1.5 text-sm bg-background border border-border rounded-md focus:outline-none focus:ring-1 focus:ring-primary"
              />
              <button
                onClick={() => {
                  if (customModel.trim()) updateSetting.mutate({ key: "llm_model", value: customModel.trim() });
                }}
                disabled={!customModel.trim() || updateSetting.isPending}
                className="px-3 py-1.5 text-sm bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50"
              >
                Save
              </button>
            </div>
          )}

          <p className="text-xs text-muted-foreground">
            Active: <strong>{settings?.llm_provider}</strong> / <strong>{settings?.llm_model}</strong>
          </p>
        </div>

        <div className="flex items-center gap-3 pt-2 border-t border-border">
          <button
            onClick={testLLM}
            disabled={testing}
            className="flex items-center gap-2 px-4 py-2 text-sm bg-primary text-primary-foreground rounded-md hover:bg-primary/90 disabled:opacity-50 transition-colors"
          >
            <Play className="w-3.5 h-3.5" />
            {testing ? "Testing..." : "Test Connection"}
          </button>
          {testResult && (
            <div className="flex items-center gap-2 text-sm">
              {testResult.status === "ok" ? (
                <>
                  <CheckCircle className="w-4 h-4 text-green-500" />
                  <span className="text-green-600 dark:text-green-400">
                    {testResult.model} — {testResult.reply}
                  </span>
                </>
              ) : (
                <>
                  <XCircle className="w-4 h-4 text-red-500" />
                  <span className="text-red-600 dark:text-red-400">{testResult.detail}</span>
                </>
              )}
            </div>
          )}
        </div>
      </section>

      {/* Data Sources */}
      <section className="bg-card border border-border rounded-lg p-6 space-y-4">
        <h2 className="font-semibold flex items-center gap-2">
          <RefreshCw className="w-4 h-4" /> Data Sources
        </h2>
        <div className="space-y-3 text-sm">
          <div className="flex items-center justify-between">
            <div>
              <div className="font-medium">Congress.gov Poll Interval</div>
              <div className="text-xs text-muted-foreground">How often to check for new bills</div>
            </div>
            <select
              value={settings?.congress_poll_interval_minutes}
              onChange={(e) => updateSetting.mutate({ key: "congress_poll_interval_minutes", value: e.target.value })}
              className="px-3 py-1.5 text-sm bg-background border border-border rounded-md"
            >
              <option value="15">Every 15 min</option>
              <option value="30">Every 30 min</option>
              <option value="60">Every hour</option>
              <option value="360">Every 6 hours</option>
            </select>
          </div>
          <div className="flex items-center justify-between py-2 border-t border-border">
            <div>
              <div className="font-medium">NewsAPI.org</div>
              <div className="text-xs text-muted-foreground">100 requests/day free tier</div>
            </div>
            <span className={`text-xs font-medium ${settings?.newsapi_enabled ? "text-green-500" : "text-muted-foreground"}`}>
              {settings?.newsapi_enabled ? "Configured" : "Not configured"}
            </span>
          </div>
          <div className="flex items-center justify-between py-2 border-t border-border">
            <div>
              <div className="font-medium">Google Trends</div>
              <div className="text-xs text-muted-foreground">Zeitgeist scoring via pytrends</div>
            </div>
            <span className={`text-xs font-medium ${settings?.pytrends_enabled ? "text-green-500" : "text-muted-foreground"}`}>
              {settings?.pytrends_enabled ? "Enabled" : "Disabled"}
            </span>
          </div>
        </div>
      </section>

      {/* API Health */}
      <section className="bg-card border border-border rounded-lg p-6 space-y-4">
        <div className="flex items-center justify-between">
          <h2 className="font-semibold">External API Health</h2>
          <button
            onClick={testApiHealth}
            disabled={healthTesting}
            className="flex items-center gap-2 px-3 py-1.5 text-sm bg-muted hover:bg-accent rounded-md transition-colors disabled:opacity-50"
          >
            <RefreshCw className={`w-3.5 h-3.5 ${healthTesting ? "animate-spin" : ""}`} />
            {healthTesting ? "Testing…" : "Run Tests"}
          </button>
        </div>

        {healthData ? (
          <div className="divide-y divide-border">
            {[
              { key: "congress_gov", label: "Congress.gov API" },
              { key: "govinfo", label: "GovInfo API" },
              { key: "newsapi", label: "NewsAPI.org" },
              { key: "google_news", label: "Google News RSS" },
            ].map(({ key, label }) => {
              const r = healthData[key];
              if (!r) return null;
              return (
                <div key={key} className="flex items-start justify-between py-3 gap-4">
                  <div>
                    <div className="text-sm font-medium">{label}</div>
                    <div className={`text-xs mt-0.5 ${
                      r.status === "ok" ? "text-green-600 dark:text-green-400"
                      : r.status === "skipped" ? "text-muted-foreground"
                      : "text-red-600 dark:text-red-400"
                    }`}>
                      {r.detail}
                    </div>
                  </div>
                  <div className="flex items-center gap-2 shrink-0">
                    {r.latency_ms !== undefined && (
                      <span className="text-xs text-muted-foreground">{r.latency_ms}ms</span>
                    )}
                    {r.status === "ok" && <CheckCircle className="w-4 h-4 text-green-500" />}
                    {r.status === "error" && <XCircle className="w-4 h-4 text-red-500" />}
                    {r.status === "skipped" && <span className="text-xs text-muted-foreground">—</span>}
                  </div>
                </div>
              );
            })}
          </div>
        ) : (
          <p className="text-sm text-muted-foreground">
            Click Run Tests to check connectivity to each external data source.
          </p>
        )}
      </section>

      {/* Manual Controls */}
      <section className="bg-card border border-border rounded-lg p-6 space-y-4">
        <h2 className="font-semibold">Manual Controls</h2>
        <div className="divide-y divide-border">
          {([
            {
              key: "poll",
              name: "Trigger Poll",
              description: "Check Congress.gov for newly introduced or updated bills. Runs automatically on a schedule — use this to force an immediate sync.",
              fn: adminAPI.triggerPoll,
              status: "on-demand",
            },
            {
              key: "members",
              name: "Sync Members",
              description: "Refresh all member profiles from Congress.gov including biography, current term, leadership roles, and contact information.",
              fn: adminAPI.triggerMemberSync,
              status: "on-demand",
            },
            {
              key: "trends",
              name: "Calculate Trends",
              description: "Score bill and member newsworthiness by counting recent news headlines and Google search interest. Updates the trend charts.",
              fn: adminAPI.triggerTrendScores,
              status: "on-demand",
            },
            {
              key: "actions",
              name: "Fetch Bill Actions",
              description: "Download the full legislative history (votes, referrals, amendments) for recently active bills and populate the timeline view.",
              fn: adminAPI.triggerFetchActions,
              status: "on-demand",
            },
            {
              key: "backfill-actions",
              name: "Backfill All Action Histories",
              description: "One-time catch-up: fetch action histories for all bills that were imported before this feature existed. Run once to populate timelines across your full bill archive.",
              fn: adminAPI.backfillAllActions,
              status: stats ? (stats.bills_missing_actions > 0 ? "needed" : "ok") : "on-demand",
              count: stats?.bills_missing_actions,
              countLabel: "bills missing action history",
            },
            {
              key: "sponsors",
              name: "Backfill Sponsors",
              description: "Link bill sponsors that weren't captured during the initial import. Safe to re-run — skips bills that already have a sponsor.",
              fn: adminAPI.backfillSponsors,
              status: stats ? (stats.bills_missing_sponsor > 0 ? "needed" : "ok") : "on-demand",
              count: stats?.bills_missing_sponsor,
              countLabel: "bills missing sponsor",
            },
            {
              key: "metadata",
              name: "Backfill Dates & Links",
              description: "Fill in missing introduced dates, chamber assignments, and congress.gov links by re-fetching bill detail from Congress.gov.",
              fn: adminAPI.backfillMetadata,
              status: stats ? (stats.bills_missing_metadata > 0 ? "needed" : "ok") : "on-demand",
              count: stats?.bills_missing_metadata,
              countLabel: "bills missing metadata",
            },
            {
              key: "citations",
              name: "Backfill Citations",
              description: "Regenerate AI briefs that were created before inline source citations were added. Deletes the old brief and re-runs LLM analysis using the already-stored bill text — no new Congress.gov calls.",
              fn: adminAPI.backfillCitations,
              status: stats ? (stats.uncited_briefs > 0 ? "needed" : "ok") : "on-demand",
              count: stats?.uncited_briefs,
              countLabel: "briefs need regeneration",
            },
            {
              key: "resume",
              name: "Resume Analysis",
              description: "Restart AI brief generation for bills where processing stalled or failed (e.g. after an LLM quota outage). Also re-queues document fetching for bills that have no text yet.",
              fn: adminAPI.resumeAnalysis,
              status: stats ? (stats.pending_llm > 0 ? "needed" : "ok") : "on-demand",
              count: stats?.pending_llm,
              countLabel: "bills pending analysis",
            },
          ] as Array<{
            key: string;
            name: string;
            description: string;
            fn: () => Promise<{ task_id: string }>;
            status: "ok" | "needed" | "on-demand";
            count?: number;
            countLabel?: string;
          }>).map(({ key, name, description, fn, status, count, countLabel }) => (
            <div key={key} className="flex items-start gap-3 py-3.5">
              <div className={`w-2.5 h-2.5 rounded-full mt-1 shrink-0 ${
                status === "ok" ? "bg-green-500"
                : status === "needed" ? "bg-red-500"
                : "bg-border"
              }`} />
              <div className="flex-1 min-w-0 space-y-0.5">
                <div className="flex items-center gap-2 flex-wrap">
                  <span className="text-sm font-medium">{name}</span>
                  {taskStatuses[key] === "running" ? (
                    <span className="flex items-center gap-1 text-xs text-muted-foreground">
                      <RefreshCw className="w-3 h-3 animate-spin" />
                      running
                      {taskIds[key] && (
                        <code className="font-mono opacity-60">{taskIds[key].slice(0, 8)}…</code>
                      )}
                    </span>
                  ) : taskStatuses[key] === "done" ? (
                    <span className="text-xs text-green-600 dark:text-green-400">✓ Complete</span>
                  ) : taskStatuses[key] === "error" ? (
                    <span className="text-xs text-red-600 dark:text-red-400">✗ Failed</span>
                  ) : status === "ok" ? (
                    <span className="text-xs text-green-600 dark:text-green-400">✓ Up to date</span>
                  ) : status === "needed" && count !== undefined && count > 0 ? (
                    <span className="text-xs text-red-600 dark:text-red-400">
                      ⚠ {count.toLocaleString()} {countLabel}
                    </span>
                  ) : null}
                </div>
                <p className="text-xs text-muted-foreground leading-relaxed">{description}</p>
              </div>
              <button
                onClick={() => trigger(key, fn)}
                disabled={taskStatuses[key] === "running"}
                className="shrink-0 flex items-center gap-1.5 px-3 py-1.5 text-xs bg-muted hover:bg-accent rounded-md transition-colors font-medium disabled:opacity-50 disabled:cursor-not-allowed"
              >
                {taskStatuses[key] === "running" ? (
                  <RefreshCw className="w-3 h-3 animate-spin" />
                ) : "Run"}
              </button>
            </div>
          ))}
        </div>
      </section>
    </div>
  );
}
