import { useNavigate, useParams } from "@tanstack/react-router";
import { motion, type Variants } from "framer-motion";
import { ChevronRight, Clock, Eye, Users } from "lucide-react";
import { useMemo, useState } from "react";
import { usePeers } from "@/api/queries";
import type { components } from "@/api/schema.d.ts";
import { Breadcrumb } from "@/components/layout/Breadcrumb";
import { EmptyState } from "@/components/shared/EmptyState";
import { ErrorAlert } from "@/components/shared/ErrorAlert";
import { JsonViewer } from "@/components/shared/JsonViewer";
import { Pagination } from "@/components/shared/Pagination";
import { Skeleton } from "@/components/shared/Skeleton";
import { SortControl, type SortDir } from "@/components/shared/SortControl";
import { MonoCaption, PageTitle } from "@/components/ui/typography";
import { useDemo } from "@/hooks/useDemo";
import { COLOR } from "@/lib/constants";

type Peer = components["schemas"]["Peer"];

type KindStyle = { bg: string; text: string; border: string };

const KIND_STYLES: Record<string, KindStyle> = {
	agent: { bg: COLOR.warningDim, text: COLOR.warning, border: COLOR.warningBorder },
	discord: { bg: "rgba(14,165,233,0.08)", text: "#38bdf8", border: "rgba(14,165,233,0.2)" },
	ai: { bg: COLOR.accentDim, text: COLOR.accentText, border: COLOR.accentBorder },
};

function peerKind(id: string): (KindStyle & { label: string }) | null {
	if (id.startsWith("agent-")) return { label: "agent", ...KIND_STYLES.agent };
	if (id.startsWith("discord-")) return { label: "discord", ...KIND_STYLES.discord };
	if (["claude", "hermes", "codex"].includes(id)) return { label: "ai", ...KIND_STYLES.ai };
	return null;
}

const SORT_OPTIONS = [
	{ value: "created_at", label: "Newest" },
	{ value: "id", label: "ID" },
];

const container: Variants = {
	hidden: { opacity: 0 },
	show: { opacity: 1, transition: { staggerChildren: 0.06 } },
};
const item: Variants = {
	hidden: { opacity: 0, y: 10 },
	show: { opacity: 1, y: 0, transition: { type: "spring", stiffness: 300, damping: 25 } },
};

export function PeerList() {
	const { mask } = useDemo();
	const { workspaceId } = useParams({ strict: false }) as { workspaceId: string };
	const [page, setPage] = useState(1);
	const [sortField, setSortField] = useState("created_at");
	const [sortDir, setSortDir] = useState<SortDir>("desc");
	const [expandedMeta, setExpandedMeta] = useState<Set<string>>(new Set());
	const [activeFilters, setActiveFilters] = useState<Set<string>>(new Set());
	const navigate = useNavigate();
	const { data, isLoading, error } = usePeers(workspaceId, page);

	const peers: Peer[] = (data as { items?: Peer[] } | undefined)?.items ?? [];
	const totalPages = (data as { pages?: number } | undefined)?.pages ?? 1;
	const total = (data as { total?: number } | undefined)?.total ?? 0;

	const availableLabels = useMemo(() => {
		const labels = new Set<string>();
		for (const peer of peers) {
			const kind = peerKind(peer.id);
			if (kind) labels.add(kind.label);
		}
		return labels;
	}, [peers]);

	const sorted = useMemo(() => {
		return [...peers].sort((a, b) => {
			let cmp = 0;
			if (sortField === "created_at") {
				cmp = new Date(a.created_at).getTime() - new Date(b.created_at).getTime();
			} else if (sortField === "id") {
				cmp = a.id.localeCompare(b.id);
			}
			return sortDir === "asc" ? cmp : -cmp;
		});
	}, [peers, sortField, sortDir]);

	const filtered = useMemo(() => {
		if (activeFilters.size === 0) return sorted;
		return sorted.filter((peer) => {
			const kind = peerKind(peer.id);
			return kind ? activeFilters.has(kind.label) : false;
		});
	}, [sorted, activeFilters]);

	function toggleFilter(label: string) {
		setActiveFilters((prev) => {
			const next = new Set(prev);
			next.has(label) ? next.delete(label) : next.add(label);
			return next;
		});
	}

	function handleSort(field: string, dir: SortDir) {
		setSortField(field);
		setSortDir(dir);
	}

	return (
		<div className="page-container">
			<motion.div initial={{ opacity: 0, y: -8 }} animate={{ opacity: 1, y: 0 }} className="mb-6">
				<Breadcrumb />
				<div className="flex items-center gap-2 mb-1">
					<Users className="w-5 h-5" style={{ color: COLOR.accent }} strokeWidth={1.5} />
					<PageTitle>Peers</PageTitle>
					{total > 0 && (
						<span
							className="ml-1 text-xs font-mono px-2 py-0.5 rounded-full"
							style={{
								background: COLOR.accentSubtle,
								color: COLOR.accentText,
								border: `1px solid ${COLOR.accentBorder}`,
							}}
						>
							{total}
						</span>
					)}
					<div className="ml-auto">
						<SortControl
							options={SORT_OPTIONS}
							field={sortField}
							dir={sortDir}
							onChange={handleSort}
						/>
					</div>
				</div>
				<MonoCaption className="mt-0.5" as="p">
					{mask(workspaceId)}
				</MonoCaption>
			</motion.div>

			{availableLabels.size > 0 && (
				<div className="flex items-center gap-2 flex-wrap mb-4">
					{[...availableLabels].map((label) => {
						const style = KIND_STYLES[label];
						const active = activeFilters.has(label);
						return (
							<button
								key={label}
								type="button"
								onClick={() => toggleFilter(label)}
								className="text-xs font-mono px-2 py-1 rounded transition-opacity hover:opacity-90"
								style={{
									background: active ? style.bg : "transparent",
									color: active ? style.text : "var(--text-4)",
									border: `1px solid ${active ? style.border : "var(--border)"}`,
								}}
							>
								{label}
							</button>
						);
					})}
					{activeFilters.size > 0 && (
						<button
							type="button"
							onClick={() => setActiveFilters(new Set())}
							className="text-xs font-mono px-2 py-1 rounded transition-opacity hover:opacity-80"
							style={{ color: "var(--text-4)" }}
						>
							clear
						</button>
					)}
				</div>
			)}

			<ErrorAlert error={error instanceof Error ? error : null} />
			{isLoading && <PeerListSkeleton />}

			{!isLoading && peers.length === 0 && (
				<EmptyState
					icon={Users}
					title="No peers found"
					description="No peers exist in this workspace."
				/>
			)}

			{!isLoading && peers.length > 0 && filtered.length === 0 && (
				<EmptyState
					icon={Users}
					title="No peers match"
					description="No peers match the selected filters."
				/>
			)}

			{!isLoading && filtered.length > 0 && (
				<>
					<motion.div
						variants={container}
						initial="hidden"
						animate="show"
						className="grid grid-cols-1 sm:grid-cols-2 gap-2"
					>
						{filtered.map((peer) => {
							const kind = peerKind(peer.id);
							const metaKeys = Object.keys(peer.metadata ?? {});
							const hasMeta = metaKeys.length > 0;
							const metaOpen = expandedMeta.has(peer.id);

							function toggleMeta(e: React.MouseEvent) {
								e.stopPropagation();
								setExpandedMeta((prev) => {
									const next = new Set(prev);
									next.has(peer.id) ? next.delete(peer.id) : next.add(peer.id);
									return next;
								});
							}

							return (
								<motion.div
									key={peer.id}
									variants={item}
									className="rounded-xl overflow-hidden group"
									style={{
										background: COLOR.cardBaseBg,
										border: `1px solid ${COLOR.cardBaseBorder}`,
									}}
									whileHover={{
										background: COLOR.accentDimHover,
										borderColor: COLOR.accentBorder,
									}}
								>
									<button
										type="button"
										onClick={() =>
											navigate({
												to: "/workspaces/$workspaceId/peers/$peerId",
												params: { workspaceId, peerId: peer.id } as never,
											})
										}
										className="text-left w-full px-5 py-4"
									>
										<div className="flex items-center justify-between mb-1">
											<span
												className="font-mono text-sm font-medium truncate"
												style={{ color: COLOR.accentSoft }}
											>
												{mask(peer.id)}
											</span>
											<ChevronRight
												className="w-4 h-4 shrink-0 ml-2 opacity-30 group-hover:opacity-70 transition-opacity"
												style={{ color: COLOR.accent }}
												strokeWidth={1.5}
											/>
										</div>
										<div className="flex items-center gap-2 flex-wrap">
											{kind && (
												<span
													className="text-xs font-mono px-1.5 py-0.5 rounded"
													style={{
														background: kind.bg,
														color: kind.text,
														border: `1px solid ${kind.border}`,
													}}
												>
													{kind.label}
												</span>
											)}
											{(peer.configuration as { observe_me?: boolean } | null)?.observe_me && (
												<div className="flex items-center gap-1">
													<Eye
														className="w-3 h-3"
														style={{ color: COLOR.accentText }}
														strokeWidth={1.5}
													/>
													<span className="text-xs" style={{ color: COLOR.accentText }}>
														observed
													</span>
												</div>
											)}
											{peer.created_at && (
												<div className="flex items-center gap-1">
													<Clock
														className="w-3 h-3"
														style={{ color: COLOR.dimIcon }}
														strokeWidth={1.5}
													/>
													<MonoCaption>{new Date(peer.created_at).toLocaleString()}</MonoCaption>
												</div>
											)}
										</div>
									</button>

									{hasMeta && (
										<>
											<button
												type="button"
												onClick={toggleMeta}
												className="w-full flex items-center gap-1.5 px-5 py-1.5 text-xs font-mono transition-opacity hover:opacity-80"
												style={{
													borderTop: `1px solid ${COLOR.cardBaseBorder}`,
													color: COLOR.dimText,
												}}
											>
												<ChevronRight
													className="w-3 h-3 transition-transform duration-150"
													style={{ transform: metaOpen ? "rotate(90deg)" : "rotate(0deg)" }}
													strokeWidth={2}
												/>
												{metaKeys.length} metadata key{metaKeys.length !== 1 ? "s" : ""}
											</button>
											{metaOpen && (
												<div className="px-4 pb-4">
													<JsonViewer data={peer.metadata} maxHeight="200px" />
												</div>
											)}
										</>
									)}
								</motion.div>
							);
						})}
					</motion.div>
					<Pagination page={page} totalPages={totalPages} onPageChange={setPage} />
				</>
			)}
		</div>
	);
}

function PeerListSkeleton() {
	return (
		<div aria-hidden="true">
			<div className="grid grid-cols-1 sm:grid-cols-2 gap-2">
				{Array.from({ length: 6 }).map((_, index) => (
					<div
						key={index}
						className="rounded-xl px-5 py-4"
						style={{
							background: COLOR.cardBaseBg,
							border: `1px solid ${COLOR.cardBaseBorder}`,
						}}
					>
						<div className="flex items-center justify-between">
							<Skeleton accent className="h-4 w-40 rounded" />
							<Skeleton className="h-4 w-4 rounded" />
						</div>
						<div className="mt-3 flex items-center gap-2 flex-wrap">
							<Skeleton className="h-5 w-14 rounded-full" />
							<Skeleton className="h-5 w-12 rounded-full" />
						</div>
						<div className="mt-3 flex items-center gap-2">
							<Skeleton className="h-3 w-3 rounded-full" />
							<Skeleton className="h-3 w-28 rounded" />
						</div>
					</div>
				))}
			</div>
			<div className="mt-4 flex items-center justify-between">
				<Skeleton className="h-8 w-20 rounded-lg" />
				<Skeleton className="h-4 w-16 rounded" />
				<Skeleton className="h-8 w-20 rounded-lg" />
			</div>
		</div>
	);
}
