"use client";

import { useState } from "react";
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
import { useParams, useRouter } from "next/navigation";
import Link from "next/link";
import { api, Server } from "@/lib/api";
import { Badge, Button, Card, CardHeader, CardTitle } from "@/components/ui";
import { Table, Thead, Tbody, Tr, Th, Td } from "@/components/ui";

function AssignModal({
  keyId,
  assignedServerIds,
  onClose,
}: {
  keyId: string;
  assignedServerIds: string[];
  onClose: () => void;
}) {
  const queryClient = useQueryClient();
  const [selectedServer, setSelectedServer] = useState("");

  const { data: servers } = useQuery({
    queryKey: ["servers"],
    queryFn: () => api.listServers(),
  });

  const { mutate: assign, isPending, error } = useMutation({
    mutationFn: () => api.assignKey(keyId, selectedServer),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["keys", keyId] });
      queryClient.invalidateQueries({ queryKey: ["servers"] });
      onClose();
    },
  });

  const availableServers = servers?.filter(
    (s: Server) => !assignedServerIds.includes(s.server_id)
  );

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center bg-black/60 p-4 backdrop-blur-sm">
      <div className="w-full max-w-md rounded-xl border border-border bg-surface p-6">
        <h2 className="mb-4 text-lg font-semibold text-text-primary">Assign Key to Server</h2>

        {error && (
          <div className="mb-4 rounded-lg border border-danger/30 bg-danger/10 px-3 py-2 text-sm text-danger">
            {(error as Error).message}
          </div>
        )}

        <div className="mb-4">
          <label className="mb-1.5 block text-sm font-medium text-text-secondary">
            Select Server
          </label>
          {!availableServers || availableServers.length === 0 ? (
            <p className="text-sm text-text-secondary">
              All servers already have this key assigned.
            </p>
          ) : (
            <select
              value={selectedServer}
              onChange={(e) => setSelectedServer(e.target.value)}
              className="w-full rounded-lg border border-border bg-surface-2 px-3 py-2 text-sm text-text-primary focus:border-accent focus:outline-none focus:ring-1 focus:ring-accent"
            >
              <option value="">Choose a server...</option>
              {availableServers.map((s: Server) => (
                <option key={s.server_id} value={s.server_id}>
                  {s.hostname} ({s.ip_address})
                </option>
              ))}
            </select>
          )}
        </div>

        <div className="flex justify-end gap-3">
          <Button variant="ghost" onClick={onClose}>Cancel</Button>
          <Button
            variant="primary"
            loading={isPending}
            disabled={!selectedServer}
            onClick={() => assign()}
          >
            Assign Key
          </Button>
        </div>
      </div>
    </div>
  );
}

function PrivateKeyCard({ keyId }: { keyId: string }) {
  const [revealed, setRevealed] = useState(false);
  const [privateKey, setPrivateKey] = useState<string | null>(null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [copied, setCopied] = useState(false);

  async function reveal() {
    setLoading(true);
    setError(null);
    try {
      const res = await api.getPrivateKey(keyId);
      setPrivateKey(res.private_key);
      setRevealed(true);
    } catch (e) {
      setError((e as Error).message);
    } finally {
      setLoading(false);
    }
  }

  function download() {
    if (!privateKey) return;
    const blob = new Blob([privateKey], { type: "text/plain" });
    const url = URL.createObjectURL(blob);
    const a = document.createElement("a");
    a.href = url;
    a.download = `${keyId}.pem`;
    a.click();
    URL.revokeObjectURL(url);
  }

  async function copy() {
    if (!privateKey) return;
    await navigator.clipboard.writeText(privateKey);
    setCopied(true);
    setTimeout(() => setCopied(false), 2000);
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>Private Key</CardTitle>
        {revealed && (
          <div className="flex gap-2">
            <button
              onClick={copy}
              className="rounded-md border border-border bg-surface-2 px-2.5 py-1 text-xs font-medium text-text-secondary transition-colors hover:border-accent/50 hover:text-text-primary"
            >
              {copied ? <span className="text-success">Copied!</span> : "Copy"}
            </button>
            <button
              onClick={download}
              className="rounded-md border border-border bg-surface-2 px-2.5 py-1 text-xs font-medium text-text-secondary transition-colors hover:border-accent/50 hover:text-text-primary"
            >
              Download .pem
            </button>
          </div>
        )}
      </CardHeader>

      {error && (
        <div className="mb-3 rounded-lg border border-danger/30 bg-danger/10 px-3 py-2 text-xs text-danger">
          {error}
        </div>
      )}

      {!revealed ? (
        <div className="flex flex-col items-center gap-3 py-4">
          <p className="text-center text-xs text-text-tertiary">
            Stored encrypted (AES-256-GCM). Click to decrypt and display.
          </p>
          <Button variant="secondary" size="sm" loading={loading} onClick={reveal}>
            <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
              <path strokeLinecap="round" strokeLinejoin="round" d="M2.036 12.322a1.012 1.012 0 010-.639C3.423 7.51 7.36 4.5 12 4.5c4.638 0 8.573 3.007 9.963 7.178.07.207.07.431 0 .639C20.577 16.49 16.64 19.5 12 19.5c-4.638 0-8.573-3.007-9.964-7.178z" />
              <path strokeLinecap="round" strokeLinejoin="round" d="M15 12a3 3 0 11-6 0 3 3 0 016 0z" />
            </svg>
            Reveal Private Key
          </Button>
        </div>
      ) : (
        <div className="rounded-lg border border-border bg-well p-3">
          <pre className="overflow-x-auto whitespace-pre-wrap break-all font-mono text-xs text-text-secondary leading-relaxed">
            {privateKey}
          </pre>
        </div>
      )}
    </Card>
  );
}

export default function KeyDetailPage() {
  const params = useParams();
  const router = useRouter();
  const queryClient = useQueryClient();
  const keyId = params.id as string;
  const [showAssign, setShowAssign] = useState(false);
  const [confirmDelete, setConfirmDelete] = useState(false);
  const [copiedKey, setCopiedKey] = useState(false);

  const { data: key, isLoading, error } = useQuery({
    queryKey: ["keys", keyId],
    queryFn: () => api.getKey(keyId),
  });

  const { mutate: revokeKey } = useMutation({
    mutationFn: (serverId: string) => api.revokeKey(keyId, serverId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["keys", keyId] });
      queryClient.invalidateQueries({ queryKey: ["servers"] });
    },
  });

  const { mutate: deleteKey, isPending: isDeleting } = useMutation({
    mutationFn: () => api.deleteKey(keyId),
    onSuccess: () => {
      queryClient.invalidateQueries({ queryKey: ["keys"] });
      router.push("/keys");
    },
  });

  const handleCopyKey = async () => {
    if (!key?.public_key) return;
    await navigator.clipboard.writeText(key.public_key);
    setCopiedKey(true);
    setTimeout(() => setCopiedKey(false), 2000);
  };

  if (isLoading) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-accent" />
      </div>
    );
  }

  if (error || !key) {
    return (
      <div className="p-4 sm:p-6 lg:p-8">
        <div className="rounded-lg border border-danger/30 bg-danger/10 p-4 text-danger">
          Key not found or failed to load.
        </div>
      </div>
    );
  }

  const activeAssignments = key.assignments?.filter((a) => !a.revoked_at) ?? [];
  const assignedServerIds = activeAssignments.map((a) => a.server_id);

  return (
    <div className="p-4 sm:p-6 lg:p-8">
      {showAssign && (
        <AssignModal
          keyId={keyId}
          assignedServerIds={assignedServerIds}
          onClose={() => setShowAssign(false)}
        />
      )}

      <div className="mb-6 flex flex-col gap-4 sm:flex-row sm:items-start sm:justify-between">
        <div className="min-w-0">
          <Link href="/keys" className="text-text-secondary hover:text-text-primary text-sm">
            ← SSH Keys
          </Link>
          <div className="mt-2 flex flex-wrap items-center gap-3">
            <h1 className="text-2xl font-bold text-text-primary">{key.label}</h1>
            <Badge variant={key.source === "generated" ? "accent" : "neutral"}>
              {key.source}
            </Badge>
          </div>
          {/* A fingerprint is one unbreakable token; without break-all it
              overflows the column rather than wrapping. */}
          <p className="mt-1 break-all font-mono text-xs text-text-secondary">{key.fingerprint}</p>
        </div>
        <div className="flex flex-wrap gap-2">
          <Button variant="secondary" onClick={() => setShowAssign(true)}>
            <svg className="h-4 w-4" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={2}>
              <path strokeLinecap="round" strokeLinejoin="round" d="M12 4.5v15m7.5-7.5h-15" />
            </svg>
            Assign to Server
          </Button>
          {!confirmDelete ? (
            <Button variant="danger" onClick={() => setConfirmDelete(true)}>
              Delete Key
            </Button>
          ) : (
            <div className="flex items-center gap-2">
              <span className="text-sm text-danger">Delete permanently?</span>
              <Button variant="danger" loading={isDeleting} onClick={() => deleteKey()}>
                Confirm
              </Button>
              <Button variant="ghost" onClick={() => setConfirmDelete(false)}>
                Cancel
              </Button>
            </div>
          )}
        </div>
      </div>

      <div className="grid grid-cols-1 gap-6 lg:grid-cols-3">
        <div className="space-y-6 lg:col-span-1">
          <Card>
            <CardHeader>
              <CardTitle>Details</CardTitle>
            </CardHeader>
            <dl className="space-y-3 text-sm">
              <div>
                <dt className="text-text-secondary">Key ID</dt>
                <dd className="mt-0.5 font-mono text-xs text-text-primary break-all">{key.key_id}</dd>
              </div>
              <div className="border-t border-border pt-3">
                <dt className="text-text-secondary">Source</dt>
                <dd className="mt-0.5 text-text-primary capitalize">{key.source}</dd>
              </div>
              {key.generated_by_server_id && (
                <div className="border-t border-border pt-3">
                  <dt className="text-text-secondary">Generated By</dt>
                  <dd className="mt-0.5">
                    <Link
                      href={`/servers/${key.generated_by_server_id}`}
                      className="font-mono text-xs text-accent hover:underline"
                    >
                      {key.generated_by_server_id}
                    </Link>
                  </dd>
                </div>
              )}
              <div className="border-t border-border pt-3">
                <dt className="text-text-secondary">Active Assignments</dt>
                <dd className="mt-0.5 text-text-primary">{activeAssignments.length}</dd>
              </div>
              <div className="border-t border-border pt-3">
                <dt className="text-text-secondary">Created</dt>
                <dd className="mt-0.5 text-text-primary">
                  {new Date(key.created_at).toLocaleString()}
                </dd>
              </div>
            </dl>
          </Card>

          <Card>
            <CardHeader>
              <CardTitle>Public Key</CardTitle>
              <button
                onClick={handleCopyKey}
                className="rounded-md border border-border bg-surface-2 px-2.5 py-1 text-xs font-medium text-text-secondary transition-colors hover:border-accent/50 hover:text-text-primary"
              >
                {copiedKey ? <span className="text-success">Copied!</span> : "Copy"}
              </button>
            </CardHeader>
            <div className="rounded-lg border border-border bg-well p-3">
              <pre className="overflow-x-auto whitespace-pre-wrap break-all font-mono text-xs text-text-secondary leading-relaxed">
                {key.public_key}
              </pre>
            </div>
          </Card>

          {key.has_private_key && <PrivateKeyCard keyId={keyId} />}
        </div>

        <div className="lg:col-span-2">
          <Card padding={false}>
            <div className="flex items-center justify-between border-b border-border px-6 py-4">
              <h2 className="text-lg font-semibold text-text-primary">
                Server Assignments
                <span className="ml-2 rounded-full bg-surface-2 px-2 py-0.5 text-xs text-text-secondary">
                  {activeAssignments.length} active
                </span>
              </h2>
            </div>

            {!key.assignments || key.assignments.length === 0 ? (
              <div className="py-16 text-center">
                <p className="text-text-secondary text-sm">Not assigned to any servers.</p>
                <Button
                  variant="secondary"
                  size="sm"
                  className="mt-3"
                  onClick={() => setShowAssign(true)}
                >
                  Assign to a server
                </Button>
              </div>
            ) : (
              <Table>
                <Thead>
                  <Tr>
                    <Th>Server</Th>
                    <Th>IP Address</Th>
                    <Th>Status</Th>
                    <Th>Assigned</Th>
                    <Th>Revoked</Th>
                    <Th />
                  </Tr>
                </Thead>
                <Tbody>
                  {key.assignments.map((assignment) => (
                    <Tr key={`${assignment.key_id}-${assignment.server_id}`}>
                      <Td label="Server">
                        <Link
                          href={`/servers/${assignment.server_id}`}
                          className="font-medium text-text-primary hover:text-accent"
                        >
                          {assignment.server?.hostname ?? assignment.server_id}
                        </Link>
                      </Td>
                      <Td label="IP Address">
                        <span className="font-mono text-xs text-text-secondary">
                          {assignment.server?.ip_address ?? "n/a"}
                        </span>
                      </Td>
                      <Td label="Status">
                        <Badge variant={assignment.revoked_at ? "danger" : "success"}>
                          {assignment.revoked_at ? "revoked" : "active"}
                        </Badge>
                      </Td>
                      <Td label="Assigned">
                        <span className="text-text-secondary text-xs">
                          {new Date(assignment.assigned_at).toLocaleDateString()}
                        </span>
                      </Td>
                      <Td label="Revoked">
                        <span className="text-text-secondary text-xs">
                          {assignment.revoked_at
                            ? new Date(assignment.revoked_at).toLocaleDateString()
                            : "n/a"}
                        </span>
                      </Td>
                      <Td>
                        {!assignment.revoked_at && (
                          <Button
                            variant="danger"
                            size="sm"
                            onClick={() => revokeKey(assignment.server_id)}
                          >
                            Revoke
                          </Button>
                        )}
                      </Td>
                    </Tr>
                  ))}
                </Tbody>
              </Table>
            )}
          </Card>
        </div>
      </div>
    </div>
  );
}
