import { Pause, Play, Trash2 } from "lucide-react";
import { type FC, useEffect, useMemo, useRef, useState } from "react";
import { useLogsGet } from "@/api/gen/logs/logs";
import type { LogEntry } from "@/api/gen/model/logEntry";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import { Card, CardContent } from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { cn } from "@/lib/utils";
import { m } from "@/paraglide/messages";

const LEVELS = ["DEBUG", "INFO", "WARN", "ERROR"] as const;
type MinLevel = (typeof LEVELS)[number];
const RANK: Record<string, number> = {
	TRACE: 0,
	DEBUG: 1,
	INFO: 2,
	WARN: 3,
	ERROR: 4,
};
const LEVEL_CLASS: Record<string, string> = {
	ERROR: "text-red-400",
	WARN: "text-amber-400",
	INFO: "text-sky-300",
	DEBUG: "text-muted-foreground",
	TRACE: "text-muted-foreground",
};

const KEEP = 5_000; // accumulated entries (client memory bound)
const SHOW = 1_000; // rendered rows (DOM bound)

/**
 * Container: cursor-paged log polling. A non-empty page advances the cursor — a new query key,
 * so the next page fetches immediately and a backlog drains fast; an empty page leaves the key
 * unchanged and `refetchInterval` paces the idle poll. Pausing (follow off) stops the interval.
 */
export const LogsSection: FC = () => {
	const [cursor, setCursor] = useState(0);
	const [entries, setEntries] = useState<LogEntry[]>([]);
	const [follow, setFollow] = useState(true);
	const [dropped, setDropped] = useState(false);

	const query = useLogsGet(
		{ after: cursor > 0 ? cursor : undefined },
		{ query: { refetchInterval: follow ? 2_000 : false } },
	);

	const data = query.data;
	useEffect(() => {
		if (!data || data.entries.length === 0) return;
		setEntries((prev) => [...prev, ...data.entries].slice(-KEEP));
		setDropped((d) => d || data.dropped);
		setCursor(data.next);
	}, [data]);

	return (
		<LogsCard
			entries={entries}
			follow={follow}
			onFollow={setFollow}
			onClear={() => {
				setEntries([]);
				setDropped(false);
			}}
			dropped={dropped}
		/>
	);
};

/** Pure log viewer: level/min filter + text search (local UI state), follow + clear controls. */
export const LogsCard: FC<{
	entries: LogEntry[];
	follow: boolean;
	onFollow: (follow: boolean) => void;
	onClear: () => void;
	dropped: boolean;
}> = ({ entries, follow, onFollow, onClear, dropped }) => {
	const [minLevel, setMinLevel] = useState<MinLevel>("DEBUG");
	const [search, setSearch] = useState("");
	const listRef = useRef<HTMLDivElement>(null);

	const filtered = useMemo(() => {
		const min = RANK[minLevel] ?? 0;
		const q = search.trim().toLowerCase();
		return entries
			.filter(
				(e) =>
					(RANK[e.level] ?? 0) >= min &&
					(q === "" ||
						e.msg.toLowerCase().includes(q) ||
						e.target.toLowerCase().includes(q)),
			)
			.slice(-SHOW);
	}, [entries, minLevel, search]);

	// Keep the tail in view while following (entries are append-only, so length is a good signal).
	useEffect(() => {
		if (!follow) return;
		const el = listRef.current;
		if (el) el.scrollTop = el.scrollHeight;
	}, [follow, filtered.length]);

	return (
		<Card>
			<CardContent className="flex flex-col gap-3 pt-6">
				<div className="flex flex-wrap items-center gap-2">
					<div className="flex items-center gap-1">
						{LEVELS.map((l) => (
							<Button
								key={l}
								size="sm"
								variant={minLevel === l ? "secondary" : "ghost"}
								onClick={() => setMinLevel(l)}
							>
								{l}
							</Button>
						))}
					</div>
					<Input
						value={search}
						onChange={(e) => setSearch(e.target.value)}
						placeholder={m.logs_search()}
						className="max-w-xs"
					/>
					<div className="ml-auto flex items-center gap-2">
						{dropped && (
							<Badge variant="secondary">{m.logs_dropped()}</Badge>
						)}
						<Button
							size="sm"
							variant={follow ? "secondary" : "outline"}
							onClick={() => onFollow(!follow)}
						>
							{follow ? (
								<Pause className="mr-1 size-3.5" />
							) : (
								<Play className="mr-1 size-3.5" />
							)}
							{follow ? m.logs_pause() : m.logs_follow()}
						</Button>
						<Button size="sm" variant="ghost" onClick={onClear}>
							<Trash2 className="mr-1 size-3.5" />
							{m.logs_clear()}
						</Button>
					</div>
				</div>

				<div
					ref={listRef}
					className="max-h-[65vh] overflow-auto rounded-md border bg-card/40 p-2 font-mono text-xs leading-5"
				>
					{filtered.length === 0 ? (
						<p className="p-2 text-muted-foreground">{m.logs_empty()}</p>
					) : (
						filtered.map((e) => (
							<div key={e.seq} className="whitespace-pre-wrap break-words">
								<span className="text-muted-foreground">
									{fmtTime(e.ts_ms)}{" "}
								</span>
								<span
									className={cn(
										"font-medium",
										LEVEL_CLASS[e.level] ?? "text-muted-foreground",
									)}
								>
									{e.level.padEnd(5)}{" "}
								</span>
								<span className="text-muted-foreground">{e.target} </span>
								<span>{e.msg}</span>
							</div>
						))
					)}
				</div>
			</CardContent>
		</Card>
	);
};

const fmtTime = (ts: number): string => {
	const d = new Date(ts);
	const p = (n: number, w = 2) => String(n).padStart(w, "0");
	return `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}.${p(d.getMilliseconds(), 3)}`;
};
