"use client";

import { Suspense } from "react";
import { useQuery } from "@tanstack/react-query";
import Link from "next/link";
import { useRouter, useSearchParams } from "next/navigation";
import { api, Server } from "@/lib/api";
import { Button, Card } from "@/components/ui";
import { Table, Thead, Tbody, Tr, Th, Td } from "@/components/ui";
import { TagChips } from "@/components/servers/TagChips";
import { TagFilterBar } from "@/components/servers/TagFilterBar";


type DotStatus = "offline" | "needs-update" | "has-package-updates" | "ok";

function resolveStatus(server: Server, latestVersion: string | undefined): DotStatus {
  if (server.status === "offline" || server.status === "pending") return "offline";
  if (latestVersion && server.agent_version && server.agent_version !== latestVersion) return "needs-update";
  if (server.available_updates && server.available_updates.length > 0) return "has-package-updates";
  return "ok";
}

// The palette has one amber, so the two update states split by meaning rather
// than by shade: a stale agent is a warning, available OS packages are just
// something waiting for you.
const DOT_CLASSES: Record<DotStatus, string> = {
  offline:             "bg-danger",
  "needs-update":      "bg-warning",
  "has-package-updates": "bg-accent",
  ok:                  "bg-success",
};

const DOT_LABELS: Record<DotStatus, string> = {
  offline:             "Offline",
  "needs-update":      "Agent needs updating",
  "has-package-updates": "Package updates available",
  ok:                  "OK",
};

function StatusDot({ status }: { status: DotStatus }) {
  return (
    <span title={DOT_LABELS[status]} className="flex items-center">
      <span className={`inline-block h-2.5 w-2.5 rounded-full ${DOT_CLASSES[status]}`} />
    </span>
  );
}

function formatLastSeen(dateStr: string): string {
  const date = new Date(dateStr);
  const now = new Date();
  const diffMs = now.getTime() - date.getTime();
  const diffSec = Math.floor(diffMs / 1000);
  const diffMin = Math.floor(diffSec / 60);
  const diffHour = Math.floor(diffMin / 60);
  const diffDay = Math.floor(diffHour / 24);

  if (diffSec < 60) return `${diffSec}s ago`;
  if (diffMin < 60) return `${diffMin}m ago`;
  if (diffHour < 24) return `${diffHour}h ago`;
  return `${diffDay}d ago`;
}

// useSearchParams opts this page into client-side bailout, which the App
// Router only permits inside a Suspense boundary — hence the wrapper at the
// bottom of this file rather than a bare default export.
function ServersPageBody() {
  const searchParams = useSearchParams();
  const router = useRouter();

  // The filter lives in the URL so a filtered fleet view is a shareable link.
  const selected = Object.fromEntries(
    searchParams
      .getAll("tag")
      .map((t) => t.split(":"))
      .filter((p) => p.length === 2),
  ) as Record<string, string>;

  function setSelected(next: Record<string, string>) {
    const qs = Object.entries(next)
      .map(([k, v]) => `tag=${encodeURIComponent(`${k}:${v}`)}`)
      .join("&");
    router.replace(qs ? `/servers?${qs}` : "/servers");
  }

  const { data: servers, isLoading, error } = useQuery({
    queryKey: ["servers", selected],
    queryFn: () => api.listServers(selected),
    refetchInterval: 30_000,
  });

  const { data: latestVersionData } = useQuery({
    queryKey: ["agent-latest-version"],
    queryFn: api.getLatestAgentVersion,
    staleTime: 5 * 60_000,
  });
  const latestVersion = latestVersionData?.version;

  return (
    <div className="p-4 sm:p-6 lg:p-8">
      <div className="mb-6 flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
        <div>
          <h1 className="text-2xl font-bold text-text-primary">Servers</h1>
          <p className="mt-1 text-sm text-text-secondary">
            {servers?.length ?? 0} registered server{servers?.length !== 1 ? "s" : ""}
          </p>
        </div>
        <Link href="/servers/new">
          <Button variant="primary">
            <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>
            Add Server
          </Button>
        </Link>
      </div>

      <TagFilterBar value={selected} onChange={setSelected} />

      <Card padding={false}>
        {isLoading ? (
          <div className="flex items-center justify-center py-20">
            <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-accent" />
          </div>
        ) : error ? (
          <div className="py-20 text-center text-danger">
            Failed to load servers. Is the backend running?
          </div>
        ) : servers && servers.length > 0 ? (
          <Table>
            <Thead>
              <Tr>
                <Th>Hostname</Th>
                <Th>IP Address</Th>
                <Th>OS</Th>
                <Th>Tags</Th>
                <Th>Status</Th>
                <Th>Last Seen</Th>
                <Th />
              </Tr>
            </Thead>
            <Tbody>
              {servers.map((server: Server) => (
                <Tr key={server.server_id}>
                  <Td label="Hostname">
                    <span className="font-medium text-text-primary">
                      {server.hostname}
                    </span>
                  </Td>
                  <Td label="IP Address">
                    <span className="font-mono text-text-secondary">
                      {server.ip_address}
                    </span>
                  </Td>
                  <Td label="OS">
                    <span className="text-text-secondary">{server.os_info}</span>
                  </Td>
                  <Td label="Tags">
                    <TagChips serverId={server.server_id} tags={server.tags} />
                  </Td>
                  <Td label="Status">
                    <StatusDot status={resolveStatus(server, latestVersion)} />
                  </Td>
                  <Td label="Last Seen">
                    <span className="text-text-secondary">
                      {server.last_seen
                        ? formatLastSeen(server.last_seen)
                        : "Never"}
                    </span>
                  </Td>
                  <Td>
                    <Link href={`/servers/${server.server_id}`}>
                      <Button variant="ghost" size="sm">
                        View →
                      </Button>
                    </Link>
                  </Td>
                </Tr>
              ))}
            </Tbody>
          </Table>
        ) : (
          <div className="py-20 text-center">
            <div className="mx-auto mb-4 flex h-12 w-12 items-center justify-center rounded-full bg-surface-2">
              <svg className="h-6 w-6 text-text-secondary" fill="none" viewBox="0 0 24 24" stroke="currentColor" strokeWidth={1.5}>
                <path strokeLinecap="round" strokeLinejoin="round" d="M5.25 14.25h13.5m-13.5 0a3 3 0 01-3-3m3 3a3 3 0 100 6h13.5a3 3 0 100-6m-16.5-3a3 3 0 013-3h13.5a3 3 0 013 3m-19.5 0a4.5 4.5 0 01.9-2.7L5.737 5.1a3.375 3.375 0 012.7-1.35h7.126c1.062 0 2.062.5 2.7 1.35l2.587 3.45a4.5 4.5 0 01.9 2.7m0 0a3 3 0 01-3 3m0 3h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008zm-3 6h.008v.008h-.008v-.008zm0-6h.008v.008h-.008v-.008z" />
              </svg>
            </div>
            <p className="text-text-secondary">No servers registered yet.</p>
            <Link href="/servers/new">
              <Button variant="primary" size="sm" className="mt-4">
                Add your first server
              </Button>
            </Link>
          </div>
        )}
      </Card>
    </div>
  );
}

export default function ServersPage() {
  return (
    <Suspense
      fallback={
        <div className="flex items-center justify-center p-20">
          <div className="h-8 w-8 animate-spin rounded-full border-2 border-border border-t-accent" />
        </div>
      }
    >
      <ServersPageBody />
    </Suspense>
  );
}
