import { json, type LoaderFunctionArgs, type ActionFunctionArgs } from "@remix-run/node";
import { useLoaderData, useActionData, Form, useNavigation } from "@remix-run/react";
import { useState, useEffect, useCallback } from "react";

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

interface ComponentUpdate {
  component_id: string;
  current_version?: string;
  available_version: string;
  changelog: string;
  download_size?: number;
  compatible: boolean;
  incompatible_reason?: string;
}

interface PluginUpdate {
  plugin_id: string;
  current_version: string;
  available_version: string;
  changelog: string;
  download_size?: number;
  source_repo: string;
}

interface UpdateInfo {
  update_available: boolean;
  current_version: string;
  latest_version?: string;
  release_date?: string;
  changelog?: string;
  is_prerelease: boolean;
  download_size?: number;
  message?: string;
  components?: ComponentUpdate[];
  plugins?: PluginUpdate[];
}

interface ComponentProgress {
  component_id: string;
  status: string;
  download_progress: number;
  error_message?: string;
}

interface UpdateProgress {
  status: string;
  current_version: string;
  available_version?: string;
  download_progress: number;
  error_message?: string;
  last_check?: string;
  active_component?: string;
  components?: ComponentProgress[];
}

interface InstalledComponent {
  component_id: string;
  version: string;
  installed_at: string;
  install_path: string;
  platform?: string;
  python_version?: string;
}

interface ManifestData {
  system_version: string;
  components: Record<string, InstalledComponent>;
  last_updated: string;
}

interface OsInfo {
  debian_version: string;
  debian_codename: string;
  kernel: string;
  architecture: string;
  uptime_seconds: number;
  hostname: string;
  last_apt_update: string | null;
  auto_security_updates: boolean;
  reboot_required: boolean;
}

interface OsPackageUpdate {
  name: string;
  current_version: string;
  available_version: string;
  architecture: string;
  origin: string;
}

interface OsUpdatesData {
  count: number;
  packages: OsPackageUpdate[];
  upgrading: boolean;
}

// ---------------------------------------------------------------------------
// Loader / Action
// ---------------------------------------------------------------------------

export async function loader({ request }: LoaderFunctionArgs) {
  try {
    const [progressRes, manifestRes, osInfoRes, osUpdatesRes] = await Promise.all([
      fetch("http://localhost:8000/api/updates/progress"),
      fetch("http://localhost:8000/api/updates/components"),
      fetch("http://localhost:8000/api/system/os/info").catch(() => null),
      fetch("http://localhost:8000/api/system/os/updates").catch(() => null),
    ]);

    const progressInfo = await progressRes.json();
    const manifest = manifestRes.ok ? await manifestRes.json() : null;
    const osInfo = osInfoRes?.ok ? await osInfoRes.json() : null;
    const osUpdates = osUpdatesRes?.ok ? await osUpdatesRes.json() : null;

    return json({ progressInfo, manifest, osInfo, osUpdates, error: null });
  } catch (error) {
    console.error("Error loading update info:", error);
    return json({
      progressInfo: null,
      manifest: null,
      osInfo: null,
      osUpdates: null,
      error: "Failed to load update information",
    });
  }
}

interface ActionResult {
  success: boolean;
  intent?: string;
  message?: string;
  data?: unknown;
}

export async function action({ request }: ActionFunctionArgs) {
  const formData = await request.formData();
  const intent = formData.get("_action") as string;
  const componentId = formData.get("component_id") as string | null;

  try {
    if (intent === "check_updates") {
      const response = await fetch("http://localhost:8000/api/updates/check");
      const data = await response.json();
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "download_all") {
      const response = await fetch("http://localhost:8000/api/updates/download", {
        method: "POST",
      });
      const data = await response.json();
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "install_all") {
      const response = await fetch("http://localhost:8000/api/updates/install", {
        method: "POST",
      });
      const data = await response.json();
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "download_component" && componentId) {
      const response = await fetch(
        `http://localhost:8000/api/updates/components/${componentId}/download`,
        { method: "POST" }
      );
      if (!response.ok) {
        const err = await response.json();
        return json<ActionResult>({ success: false, intent, message: err.detail || "Download failed" });
      }
      const data = await response.json();
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "install_component" && componentId) {
      const response = await fetch(
        `http://localhost:8000/api/updates/components/${componentId}/install`,
        { method: "POST" }
      );
      if (!response.ok) {
        const err = await response.json();
        return json<ActionResult>({ success: false, intent, message: err.detail || "Install failed" });
      }
      const data = await response.json();
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "rollback_component" && componentId) {
      const response = await fetch(
        `http://localhost:8000/api/updates/components/${componentId}/rollback`,
        { method: "POST" }
      );
      if (!response.ok) {
        const err = await response.json();
        return json<ActionResult>({ success: false, intent, message: err.detail || "Rollback failed" });
      }
      const data = await response.json();
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "os_update") {
      const securityOnly = formData.get("security_only") === "true";
      const response = await fetch("http://localhost:8000/api/system/os/update", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ security_only: securityOnly }),
      });
      const data = await response.json();
      if (!response.ok) {
        return json<ActionResult>({ success: false, intent, message: data.detail || "OS update failed" });
      }
      return json<ActionResult>({ success: true, intent, data });
    }

    if (intent === "toggle_auto_updates") {
      const enabled = formData.get("enabled") === "true";
      const response = await fetch("http://localhost:8000/api/system/os/auto-updates", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ enabled }),
      });
      const data = await response.json();
      if (!response.ok) {
        return json<ActionResult>({ success: false, intent, message: data.detail || "Toggle failed" });
      }
      return json<ActionResult>({ success: true, intent, data });
    }

    return json<ActionResult>({ success: false, message: "Unknown action" });
  } catch (error: any) {
    return json<ActionResult>({ success: false, message: error.message || "Action failed" });
  }
}

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

const COMPONENT_LABELS: Record<string, { name: string; icon: string }> = {
  pm3: { name: "Proxmark3", icon: "\uD83D\uDD13" },
  frontend: { name: "Frontend", icon: "\uD83C\uDF10" },
  backend: { name: "Backend", icon: "\u2699\uFE0F" },
  theme: { name: "Themes", icon: "\uD83C\uDFA8" },
};

function componentLabel(id: string) {
  return COMPONENT_LABELS[id] || { name: id, icon: "\uD83D\uDCE6" };
}

function formatBytes(bytes: number) {
  if (bytes === 0) return "0 B";
  const k = 1024;
  const sizes = ["B", "KB", "MB", "GB"];
  const i = Math.floor(Math.log(bytes) / Math.log(k));
  return (bytes / Math.pow(k, i)).toFixed(1) + " " + sizes[i];
}

function formatDate(dateString: string) {
  return new Date(dateString).toLocaleDateString("en-US", {
    year: "numeric",
    month: "short",
    day: "numeric",
  });
}

function formatUptime(seconds: number): string {
  const days = Math.floor(seconds / 86400);
  const hours = Math.floor((seconds % 86400) / 3600);
  const mins = Math.floor((seconds % 3600) / 60);
  if (days > 0) return `${days}d ${hours}h`;
  if (hours > 0) return `${hours}h ${mins}m`;
  return `${mins}m`;
}

function statusColor(status: string) {
  const map: Record<string, string> = {
    idle: "var(--color-text-muted)",
    checking: "var(--color-primary)",
    available: "var(--color-accent)",
    downloading: "var(--color-primary)",
    installing: "var(--color-warning)",
    complete: "var(--color-success)",
    failed: "var(--color-error)",
    rolling_back: "var(--color-warning)",
  };
  return map[status] || "var(--color-text-muted)";
}

function StatusBadge({ status }: { status: string }) {
  const color = statusColor(status);
  const label = status === "rolling_back" ? "Rolling Back" : status.charAt(0).toUpperCase() + status.slice(1);
  return (
    <span
      className="badge"
      style={{
        backgroundColor: `${color}20`,
        color,
        border: `1px solid ${color}40`,
      }}
    >
      {label}
    </span>
  );
}

function ProgressBar({ percent }: { percent: number }) {
  return (
    <div
      style={{
        width: "100%",
        height: "6px",
        background: "var(--color-border)",
        borderRadius: "var(--radius)",
        overflow: "hidden",
        marginTop: "var(--space-2)",
      }}
    >
      <div
        style={{
          width: `${percent}%`,
          height: "100%",
          background: "linear-gradient(90deg, var(--color-primary), var(--color-accent))",
          transition: "width 0.3s ease",
        }}
      />
    </div>
  );
}

// ---------------------------------------------------------------------------
// Page
// ---------------------------------------------------------------------------

export default function Updates() {
  const { progressInfo, manifest, osInfo: initialOsInfo, osUpdates: initialOsUpdates, error } = useLoaderData<typeof loader>();
  const actionData = useActionData<typeof action>();
  const navigation = useNavigation();
  const isSubmitting = navigation.state === "submitting";

  const [progress, setProgress] = useState<UpdateProgress | null>(progressInfo);
  const [checkResult, setCheckResult] = useState<UpdateInfo | null>(null);
  const [expandedChangelogs, setExpandedChangelogs] = useState<Set<string>>(new Set());
  const [osInfo, setOsInfo] = useState<OsInfo | null>(initialOsInfo);
  const [osUpdates, setOsUpdates] = useState<OsUpdatesData | null>(initialOsUpdates);
  const [showOsPackages, setShowOsPackages] = useState(false);
  const [osUpgrading, setOsUpgrading] = useState(false);

  // Populate check results from action
  useEffect(() => {
    if (actionData?.success && actionData.intent === "check_updates" && actionData.data) {
      setCheckResult(actionData.data as UpdateInfo);
    }
    if (actionData?.intent === "os_update") {
      setOsUpgrading(false);
      // Refresh OS data after upgrade
      Promise.all([
        fetch("/api/system/os/info").then(r => r.json()).catch(() => null),
        fetch("/api/system/os/updates?refresh=true").then(r => r.json()).catch(() => null),
      ]).then(([info, updates]) => {
        if (info) setOsInfo(info);
        if (updates) setOsUpdates(updates);
      });
    }
    if (actionData?.success && actionData.intent === "toggle_auto_updates" && actionData.data) {
      const d = actionData.data as { auto_security_updates: boolean };
      setOsInfo(prev => prev ? { ...prev, auto_security_updates: d.auto_security_updates } : prev);
    }
  }, [actionData]);

  // Poll progress while downloading or installing
  useEffect(() => {
    if (
      !progress ||
      !["downloading", "installing", "rolling_back", "checking"].includes(progress.status)
    ) {
      return;
    }
    const interval = setInterval(async () => {
      try {
        const resp = await fetch("/api/updates/progress");
        const data = await resp.json();
        setProgress(data);
      } catch {
        /* ignore */
      }
    }, 1000);
    return () => clearInterval(interval);
  }, [progress?.status]);

  const toggleChangelog = useCallback((id: string) => {
    setExpandedChangelogs((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  }, []);

  if (error) {
    return (
      <div className="container">
        <h1>System Updates</h1>
        <div className="card">
          <p style={{ color: "var(--color-error)" }}>{error}</p>
        </div>
      </div>
    );
  }

  const components = checkResult?.components || [];
  const plugins = checkResult?.plugins || [];
  const hasUpdates = components.length > 0 || plugins.length > 0;
  const installedComponents = (manifest as ManifestData)?.components || {};

  return (
    <div className="container">
      {/* ---- Header ---- */}
      <div style={{ marginBottom: "var(--space-6)" }}>
        <h1 style={{ marginBottom: "var(--space-2)" }}>System Updates</h1>
        <p className="text-muted">
          Manage per-component updates from GitHub releases
        </p>
      </div>

      {/* ---- Action feedback ---- */}
      {actionData && !actionData.success && actionData.message && (
        <div
          className="card"
          style={{
            marginBottom: "var(--space-4)",
            borderColor: "var(--color-error)",
          }}
        >
          <p style={{ margin: 0, color: "var(--color-error)" }}>
            {actionData.message}
          </p>
        </div>
      )}

      {/* ---- System overview card ---- */}
      <div className="card" style={{ marginBottom: "var(--space-6)" }}>
        <div
          style={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
            flexWrap: "wrap",
            gap: "var(--space-3)",
          }}
        >
          <div>
            <div className="label" style={{ fontSize: "0.75rem" }}>System Version</div>
            <div
              style={{
                fontSize: "1.5rem",
                fontWeight: 700,
                color: "var(--color-primary)",
              }}
            >
              v{(manifest as ManifestData)?.system_version || progress?.current_version || "?"}
            </div>
            {progress?.last_check && (
              <div className="text-muted" style={{ fontSize: "0.8rem", marginTop: "var(--space-1)" }}>
                Last checked: {new Date(progress.last_check).toLocaleString()}
              </div>
            )}
          </div>

          <div style={{ display: "flex", gap: "var(--space-2)", flexWrap: "wrap" }}>
            {progress && <StatusBadge status={progress.status} />}

            <Form method="post">
              <input type="hidden" name="_action" value="check_updates" />
              <button
                type="submit"
                className="btn btn-secondary"
                disabled={isSubmitting || progress?.status === "checking"}
              >
                {progress?.status === "checking" ? "Checking..." : "Check for Updates"}
              </button>
            </Form>

            {hasUpdates && (
              <Form method="post">
                <input type="hidden" name="_action" value="download_all" />
                <button
                  type="submit"
                  className="btn btn-primary"
                  disabled={isSubmitting}
                >
                  Update All
                </button>
              </Form>
            )}
          </div>
        </div>
      </div>

      {/* ---- OS & System card ---- */}
      {osInfo && (
        <div className="card" style={{ marginBottom: "var(--space-6)" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: "var(--space-3)" }}>
            <h2 style={{ margin: 0 }}>OS & System</h2>
            {osInfo.reboot_required && (
              <span
                className="badge"
                style={{
                  backgroundColor: "var(--color-warning)20",
                  color: "var(--color-warning)",
                  border: "1px solid var(--color-warning)40",
                }}
              >
                Reboot Required
              </span>
            )}
          </div>

          {/* OS info grid */}
          <div
            style={{
              display: "grid",
              gridTemplateColumns: "repeat(auto-fill, minmax(160px, 1fr))",
              gap: "var(--space-3)",
              marginBottom: "var(--space-4)",
              fontSize: "0.875rem",
            }}
          >
            <div>
              <div className="label" style={{ fontSize: "0.7rem" }}>Debian</div>
              <div>{osInfo.debian_codename} ({osInfo.debian_version})</div>
            </div>
            <div>
              <div className="label" style={{ fontSize: "0.7rem" }}>Kernel</div>
              <div style={{ fontFamily: "var(--font-mono)", fontSize: "0.8rem" }}>{osInfo.kernel}</div>
            </div>
            <div>
              <div className="label" style={{ fontSize: "0.7rem" }}>Architecture</div>
              <div>{osInfo.architecture}</div>
            </div>
            <div>
              <div className="label" style={{ fontSize: "0.7rem" }}>Uptime</div>
              <div>{formatUptime(osInfo.uptime_seconds)}</div>
            </div>
            {osInfo.last_apt_update && (
              <div>
                <div className="label" style={{ fontSize: "0.7rem" }}>Last APT Update</div>
                <div>{formatDate(osInfo.last_apt_update)}</div>
              </div>
            )}
          </div>

          {/* Package updates summary */}
          <div
            style={{
              display: "flex",
              justifyContent: "space-between",
              alignItems: "center",
              flexWrap: "wrap",
              gap: "var(--space-2)",
              marginBottom: "var(--space-3)",
              padding: "var(--space-3)",
              background: "var(--color-bg)",
              borderRadius: "var(--radius)",
              border: "1px solid var(--color-border)",
            }}
          >
            <div>
              {osUpdates && osUpdates.count > 0 ? (
                <span style={{ color: "var(--color-accent)", fontWeight: 600 }}>
                  {osUpdates.count} package{osUpdates.count !== 1 ? "s" : ""} upgradable
                </span>
              ) : (
                <span className="text-muted">All packages up to date</span>
              )}
            </div>

            <div style={{ display: "flex", gap: "var(--space-2)", alignItems: "center", flexWrap: "wrap" }}>
              {/* Auto-updates toggle */}
              <Form method="post" style={{ display: "inline" }}>
                <input type="hidden" name="_action" value="toggle_auto_updates" />
                <input type="hidden" name="enabled" value={osInfo.auto_security_updates ? "false" : "true"} />
                <button
                  type="submit"
                  className="btn btn-secondary"
                  disabled={isSubmitting}
                  style={{ fontSize: "0.8rem", padding: "0.4rem 0.8rem" }}
                  title={osInfo.auto_security_updates ? "Disable automatic security updates" : "Enable automatic security updates"}
                >
                  Auto-updates: {osInfo.auto_security_updates ? "ON" : "OFF"}
                </button>
              </Form>

              {/* Update packages button */}
              {osUpdates && osUpdates.count > 0 && (
                <Form method="post"
                  onSubmit={() => setOsUpgrading(true)}
                >
                  <input type="hidden" name="_action" value="os_update" />
                  <input type="hidden" name="security_only" value="false" />
                  <button
                    type="submit"
                    className="btn btn-primary"
                    disabled={isSubmitting || osUpgrading || (osUpdates?.upgrading ?? false)}
                    style={{ fontSize: "0.8rem", padding: "0.4rem 0.8rem" }}
                  >
                    {osUpgrading ? "Upgrading..." : "Update Packages"}
                  </button>
                </Form>
              )}
            </div>
          </div>

          {/* Expandable package list */}
          {osUpdates && osUpdates.count > 0 && (
            <div>
              <button
                type="button"
                onClick={() => setShowOsPackages(prev => !prev)}
                style={{
                  background: "none",
                  border: "none",
                  color: "var(--color-primary)",
                  cursor: "pointer",
                  padding: 0,
                  fontSize: "0.8rem",
                  textDecoration: "underline",
                }}
              >
                {showOsPackages ? "Hide packages" : "Show packages"}
              </button>
              {showOsPackages && (
                <div
                  style={{
                    marginTop: "var(--space-2)",
                    maxHeight: "300px",
                    overflowY: "auto",
                    border: "1px solid var(--color-border)",
                    borderRadius: "var(--radius)",
                  }}
                >
                  <table style={{ width: "100%", fontSize: "0.8rem", borderCollapse: "collapse" }}>
                    <thead>
                      <tr style={{ borderBottom: "1px solid var(--color-border)" }}>
                        <th style={{ textAlign: "left", padding: "var(--space-1) var(--space-2)" }}>Package</th>
                        <th style={{ textAlign: "left", padding: "var(--space-1) var(--space-2)" }}>Current</th>
                        <th style={{ textAlign: "left", padding: "var(--space-1) var(--space-2)" }}>Available</th>
                      </tr>
                    </thead>
                    <tbody>
                      {osUpdates.packages.map((pkg) => (
                        <tr key={pkg.name} style={{ borderBottom: "1px solid var(--color-border)" }}>
                          <td style={{ padding: "var(--space-1) var(--space-2)", fontFamily: "var(--font-mono)" }}>{pkg.name}</td>
                          <td style={{ padding: "var(--space-1) var(--space-2)" }} className="text-muted">{pkg.current_version}</td>
                          <td style={{ padding: "var(--space-1) var(--space-2)", color: "var(--color-accent)" }}>{pkg.available_version}</td>
                        </tr>
                      ))}
                    </tbody>
                  </table>
                </div>
              )}
            </div>
          )}

          {/* OS upgrade result */}
          {actionData?.intent === "os_update" && actionData.success && (
            <div style={{ marginTop: "var(--space-3)", color: "var(--color-success)", fontSize: "0.875rem" }}>
              OS packages updated successfully.
              {(actionData.data as { reboot_required?: boolean })?.reboot_required && " A reboot is required."}
            </div>
          )}
        </div>
      )}

      {/* ---- Component cards ---- */}
      {components.length > 0 && (
        <div style={{ marginBottom: "var(--space-6)" }}>
          <h2 style={{ marginBottom: "var(--space-3)" }}>Component Updates</h2>
          <div style={{ display: "flex", flexDirection: "column", gap: "var(--space-3)" }}>
            {components.map((comp) => {
              const label = componentLabel(comp.component_id);
              const compProgress = progress?.components?.find(
                (c) => c.component_id === comp.component_id
              );
              const isActive = progress?.active_component === comp.component_id;

              return (
                <div
                  key={comp.component_id}
                  className="card"
                  style={{
                    borderColor: !comp.compatible
                      ? "var(--color-warning)"
                      : compProgress?.status === "failed"
                        ? "var(--color-error)"
                        : compProgress?.status === "complete"
                          ? "var(--color-success)"
                          : "var(--color-border)",
                  }}
                >
                  {/* Title row */}
                  <div
                    style={{
                      display: "flex",
                      justifyContent: "space-between",
                      alignItems: "center",
                      marginBottom: "var(--space-2)",
                    }}
                  >
                    <div style={{ display: "flex", alignItems: "center", gap: "var(--space-2)" }}>
                      <span style={{ fontSize: "1.25rem" }}>{label.icon}</span>
                      <strong>{label.name}</strong>
                    </div>
                    {compProgress && <StatusBadge status={compProgress.status} />}
                    {!comp.compatible && (
                      <span
                        className="badge"
                        style={{
                          backgroundColor: "var(--color-warning)20",
                          color: "var(--color-warning)",
                          border: "1px solid var(--color-warning)40",
                        }}
                      >
                        Incompatible
                      </span>
                    )}
                  </div>

                  {/* Versions */}
                  <div
                    style={{
                      display: "flex",
                      gap: "var(--space-4)",
                      flexWrap: "wrap",
                      fontSize: "0.875rem",
                      marginBottom: "var(--space-2)",
                    }}
                  >
                    <div>
                      <span className="text-muted">Installed: </span>
                      <span>{comp.current_version || "—"}</span>
                    </div>
                    <div>
                      <span className="text-muted">Available: </span>
                      <span style={{ color: "var(--color-accent)", fontWeight: 600 }}>
                        {comp.available_version}
                      </span>
                    </div>
                    {comp.download_size != null && comp.download_size > 0 && (
                      <div className="text-muted">{formatBytes(comp.download_size)}</div>
                    )}
                  </div>

                  {/* Incompatible reason */}
                  {!comp.compatible && comp.incompatible_reason && (
                    <div
                      style={{
                        fontSize: "0.8rem",
                        color: "var(--color-warning)",
                        marginBottom: "var(--space-2)",
                      }}
                    >
                      {comp.incompatible_reason}
                    </div>
                  )}

                  {/* Progress bar */}
                  {isActive && compProgress?.status === "downloading" && (
                    <div style={{ marginBottom: "var(--space-2)" }}>
                      <div
                        style={{
                          display: "flex",
                          justifyContent: "space-between",
                          fontSize: "0.8rem",
                        }}
                      >
                        <span>Downloading...</span>
                        <span>{Math.round(compProgress.download_progress)}%</span>
                      </div>
                      <ProgressBar percent={compProgress.download_progress} />
                    </div>
                  )}

                  {compProgress?.error_message && (
                    <div
                      style={{
                        fontSize: "0.8rem",
                        color: "var(--color-error)",
                        marginBottom: "var(--space-2)",
                      }}
                    >
                      {compProgress.error_message}
                    </div>
                  )}

                  {/* Changelog toggle */}
                  {comp.changelog && (
                    <div style={{ marginBottom: "var(--space-2)" }}>
                      <button
                        type="button"
                        onClick={() => toggleChangelog(comp.component_id)}
                        style={{
                          background: "none",
                          border: "none",
                          color: "var(--color-primary)",
                          cursor: "pointer",
                          padding: 0,
                          fontSize: "0.8rem",
                          textDecoration: "underline",
                        }}
                      >
                        {expandedChangelogs.has(comp.component_id)
                          ? "Hide changelog"
                          : "Show changelog"}
                      </button>
                      {expandedChangelogs.has(comp.component_id) && (
                        <div
                          style={{
                            marginTop: "var(--space-2)",
                            padding: "var(--space-2)",
                            background: "var(--color-bg)",
                            border: "1px solid var(--color-border)",
                            borderRadius: "var(--radius)",
                            fontSize: "0.8rem",
                            whiteSpace: "pre-wrap",
                            maxHeight: "200px",
                            overflowY: "auto",
                          }}
                        >
                          {comp.changelog}
                        </div>
                      )}
                    </div>
                  )}

                  {/* Actions */}
                  <div style={{ display: "flex", gap: "var(--space-2)", flexWrap: "wrap" }}>
                    {comp.compatible && (
                      <>
                        <Form method="post">
                          <input type="hidden" name="_action" value="download_component" />
                          <input type="hidden" name="component_id" value={comp.component_id} />
                          <button
                            type="submit"
                            className="btn btn-secondary"
                            disabled={isSubmitting || compProgress?.status === "downloading"}
                            style={{ fontSize: "0.8rem", padding: "0.4rem 0.8rem" }}
                          >
                            Download
                          </button>
                        </Form>
                        <Form method="post">
                          <input type="hidden" name="_action" value="install_component" />
                          <input type="hidden" name="component_id" value={comp.component_id} />
                          <button
                            type="submit"
                            className="btn btn-primary"
                            disabled={isSubmitting || compProgress?.status === "installing"}
                            style={{ fontSize: "0.8rem", padding: "0.4rem 0.8rem" }}
                          >
                            Install
                          </button>
                        </Form>
                      </>
                    )}
                    {compProgress?.status === "failed" && (
                      <Form method="post">
                        <input type="hidden" name="_action" value="rollback_component" />
                        <input type="hidden" name="component_id" value={comp.component_id} />
                        <button
                          type="submit"
                          className="btn btn-secondary"
                          disabled={isSubmitting}
                          style={{
                            fontSize: "0.8rem",
                            padding: "0.4rem 0.8rem",
                            borderColor: "var(--color-error)",
                            color: "var(--color-error)",
                          }}
                        >
                          Rollback
                        </button>
                      </Form>
                    )}
                  </div>
                </div>
              );
            })}
          </div>
        </div>
      )}

      {/* ---- Plugin update cards ---- */}
      {plugins.length > 0 && (
        <div style={{ marginBottom: "var(--space-6)" }}>
          <h2 style={{ marginBottom: "var(--space-3)" }}>Plugin Updates</h2>
          <div style={{ display: "flex", flexDirection: "column", gap: "var(--space-3)" }}>
            {plugins.map((p) => (
              <div key={p.plugin_id} className="card">
                <div
                  style={{
                    display: "flex",
                    justifyContent: "space-between",
                    alignItems: "center",
                    marginBottom: "var(--space-2)",
                  }}
                >
                  <strong>{p.plugin_id}</strong>
                  <StatusBadge status="available" />
                </div>
                <div
                  style={{
                    display: "flex",
                    gap: "var(--space-4)",
                    fontSize: "0.875rem",
                    marginBottom: "var(--space-2)",
                  }}
                >
                  <div>
                    <span className="text-muted">Installed: </span>{p.current_version}
                  </div>
                  <div>
                    <span className="text-muted">Available: </span>
                    <span style={{ color: "var(--color-accent)", fontWeight: 600 }}>
                      {p.available_version}
                    </span>
                  </div>
                  {p.download_size != null && (
                    <div className="text-muted">{formatBytes(p.download_size)}</div>
                  )}
                </div>
                {p.changelog && (
                  <div style={{ marginBottom: "var(--space-2)" }}>
                    <button
                      type="button"
                      onClick={() => toggleChangelog(`plugin-${p.plugin_id}`)}
                      style={{
                        background: "none",
                        border: "none",
                        color: "var(--color-primary)",
                        cursor: "pointer",
                        padding: 0,
                        fontSize: "0.8rem",
                        textDecoration: "underline",
                      }}
                    >
                      {expandedChangelogs.has(`plugin-${p.plugin_id}`)
                        ? "Hide changelog"
                        : "Show changelog"}
                    </button>
                    {expandedChangelogs.has(`plugin-${p.plugin_id}`) && (
                      <div
                        style={{
                          marginTop: "var(--space-2)",
                          padding: "var(--space-2)",
                          background: "var(--color-bg)",
                          border: "1px solid var(--color-border)",
                          borderRadius: "var(--radius)",
                          fontSize: "0.8rem",
                          whiteSpace: "pre-wrap",
                          maxHeight: "200px",
                          overflowY: "auto",
                        }}
                      >
                        {p.changelog}
                      </div>
                    )}
                  </div>
                )}
                <div className="text-muted" style={{ fontSize: "0.75rem" }}>
                  Source: {p.source_repo}
                </div>
              </div>
            ))}
          </div>
        </div>
      )}

      {/* ---- Installed components ---- */}
      {Object.keys(installedComponents).length > 0 && (
        <div style={{ marginBottom: "var(--space-6)" }}>
          <h2 style={{ marginBottom: "var(--space-3)" }}>Installed Components</h2>
          <div className="card">
            <table
              style={{
                width: "100%",
                fontSize: "0.875rem",
                borderCollapse: "collapse",
              }}
            >
              <thead>
                <tr style={{ borderBottom: "1px solid var(--color-border)" }}>
                  <th style={{ textAlign: "left", padding: "var(--space-2)" }}>Component</th>
                  <th style={{ textAlign: "left", padding: "var(--space-2)" }}>Version</th>
                  <th style={{ textAlign: "left", padding: "var(--space-2)" }}>Installed</th>
                </tr>
              </thead>
              <tbody>
                {Object.entries(installedComponents).map(([id, comp]) => {
                  const label = componentLabel(id);
                  const c = comp as InstalledComponent;
                  return (
                    <tr key={id} style={{ borderBottom: "1px solid var(--color-border)" }}>
                      <td style={{ padding: "var(--space-2)" }}>
                        {label.icon} {label.name}
                      </td>
                      <td style={{ padding: "var(--space-2)", fontFamily: "var(--font-mono)" }}>
                        {c.version}
                      </td>
                      <td style={{ padding: "var(--space-2)" }} className="text-muted">
                        {c.installed_at ? formatDate(c.installed_at) : "—"}
                      </td>
                    </tr>
                  );
                })}
              </tbody>
            </table>
          </div>
        </div>
      )}

      {/* ---- Up to date ---- */}
      {checkResult && !hasUpdates && (
        <div className="card" style={{ textAlign: "center" }}>
          <p style={{ margin: 0, color: "var(--color-success)" }}>
            All components are up to date.
          </p>
        </div>
      )}

      {/* ---- Global progress ---- */}
      {progress?.status === "complete" && (
        <div
          className="card"
          style={{
            marginTop: "var(--space-4)",
            borderColor: "var(--color-success)",
          }}
        >
          <p style={{ margin: 0, color: "var(--color-success)" }}>
            Update installed successfully. Restart the service for changes to take effect.
          </p>
        </div>
      )}

      {progress?.error_message && progress.status === "failed" && (
        <div
          className="card"
          style={{
            marginTop: "var(--space-4)",
            borderColor: "var(--color-error)",
          }}
        >
          <p style={{ margin: 0, color: "var(--color-error)" }}>
            {progress.error_message}
          </p>
        </div>
      )}
    </div>
  );
}
