import { useState } from "react";
import { ApiError } from "../../api/client";
import type { KeyMetadata, Machine } from "../../api/types";
import { Button } from "../../components/ui/Button";
import { ConfirmDialog } from "../../components/ui/ConfirmDialog";
import { Modal } from "../../components/ui/Modal";
import { Badge } from "../../components/ui/Badge";
import { Spinner } from "../../components/ui/Spinner";
import { EmptyState, ErrorState } from "../../components/ui/States";
import { useToast } from "../../components/ui/toast-context";
import { absoluteTime, relativeTime } from "../../lib/time";
import {
  useCreateMachineKey,
  useMachineKeys,
  useRevokeMachineKey,
} from "./hooks";
import { KeyRevealModal } from "./KeyRevealModal";

interface MachineKeysModalProps {
  machine: Machine | null;
  onClose: () => void;
}

function keyState(k: KeyMetadata): { tone: "ok" | "neutral"; label: string } {
  return k.revoked_at
    ? { tone: "neutral", label: "Revoked" }
    : { tone: "ok", label: "Active" };
}

/**
 * Admin-only per-agent key management. Lists key metadata (never the secret),
 * mints new keys (revealed once via KeyRevealModal), and revokes existing keys.
 */
export function MachineKeysModal({ machine, onClose }: MachineKeysModalProps) {
  const toast = useToast();
  const agentId = machine?.agent_id ?? "";

  const keysQuery = useMachineKeys(machine?.agent_id ?? null, machine != null);
  const createKey = useCreateMachineKey(agentId);
  const revokeKey = useRevokeMachineKey(agentId);

  const [revealKey, setRevealKey] = useState<string | null>(null);
  const [pendingRevoke, setPendingRevoke] = useState<KeyMetadata | null>(null);

  function handleCreate() {
    createKey.mutate(undefined, {
      onSuccess: (created) => {
        setRevealKey(created.key);
        toast.success("Key created", "Copy it now — it is shown only once.");
      },
      onError: (err) => {
        toast.error(
          "Could not create key",
          err instanceof ApiError ? err.message : "Unexpected error.",
        );
      },
    });
  }

  function handleRevoke() {
    if (!pendingRevoke) return;
    const id = pendingRevoke.id;
    revokeKey.mutate(id, {
      onSuccess: () => {
        toast.success("Key revoked");
        setPendingRevoke(null);
      },
      onError: (err) => {
        toast.error(
          "Could not revoke key",
          err instanceof ApiError ? err.message : "Unexpected error.",
        );
        setPendingRevoke(null);
      },
    });
  }

  const keys = keysQuery.data ?? [];

  return (
    <>
      <Modal
        open={machine != null && revealKey == null}
        title={
          <>
            Agent keys ·{" "}
            <span className="mono" style={{ fontWeight: 500 }}>
              {machine?.hostname}
            </span>
          </>
        }
        ariaLabel={`Agent keys for ${machine?.hostname ?? "machine"}`}
        onClose={onClose}
        wide
        footer={
          <>
            <Button variant="ghost" onClick={onClose}>
              Close
            </Button>
            <Button
              variant="primary"
              onClick={handleCreate}
              loading={createKey.isPending}
            >
              Create key
            </Button>
          </>
        }
      >
        {keysQuery.isLoading ? (
          <div style={{ padding: "24px 0", display: "grid", placeItems: "center" }}>
            <Spinner label="Loading keys" />
          </div>
        ) : keysQuery.isError ? (
          <ErrorState
            title="Failed to load keys"
            message={
              keysQuery.error instanceof ApiError
                ? keysQuery.error.message
                : "Unexpected error."
            }
          />
        ) : keys.length === 0 ? (
          <EmptyState
            title="No keys issued"
            message="This machine has no per-agent keys. Create one to enroll it as a persistent identity."
          />
        ) : (
          <table className="minitable">
            <thead>
              <tr>
                <th>State</th>
                <th>Key ID</th>
                <th>Created</th>
                <th>Last used</th>
                <th />
              </tr>
            </thead>
            <tbody>
              {keys.map((k) => {
                const s = keyState(k);
                return (
                  <tr key={k.id} className={k.revoked_at ? "key--revoked" : undefined}>
                    <td>
                      <Badge tone={s.tone} dot>
                        {s.label}
                      </Badge>
                    </td>
                    <td className="mono" title={k.id}>
                      {k.id}
                    </td>
                    <td className="mono" title={absoluteTime(k.created_at)}>
                      {relativeTime(k.created_at)}
                    </td>
                    <td className="mono" title={absoluteTime(k.last_used_at)}>
                      {k.last_used_at ? relativeTime(k.last_used_at) : "never"}
                    </td>
                    <td style={{ textAlign: "right" }}>
                      {!k.revoked_at && (
                        <Button
                          variant="danger"
                          size="sm"
                          onClick={() => setPendingRevoke(k)}
                        >
                          Revoke
                        </Button>
                      )}
                    </td>
                  </tr>
                );
              })}
            </tbody>
          </table>
        )}
      </Modal>

      <KeyRevealModal plaintextKey={revealKey} onClose={() => setRevealKey(null)} />

      <ConfirmDialog
        open={pendingRevoke != null}
        title="Revoke agent key"
        danger
        busy={revokeKey.isPending}
        confirmLabel="Revoke key"
        body={
          <span>
            Revoking this key immediately blocks any agent authenticating with
            it. This cannot be undone. Key{" "}
            <code className="mono">{pendingRevoke?.id}</code>.
          </span>
        }
        onConfirm={handleRevoke}
        onCancel={() => setPendingRevoke(null)}
      />
    </>
  );
}
