import { Alert, AlertDescription } from "@/components/ui/alert";
import { Skeleton } from "@/components/ui/skeleton";
import { SectionCard } from "../components/SectionCard";
import { useWidgetData } from "../hooks/useWidgets";
import type { WidgetInstance } from "../types";

interface Props {
	widget: WidgetInstance;
	refreshIntervalMs: number;
	description?: string;
}

interface TotalsPayload {
	total?: number;
	by_state?: Record<string, number>;
	by_direction?: {
		downloading?: number;
		uploading?: number;
	};
}

const STATE_LABELS: Record<string, string> = {
	downloading: "Downloading",
	forcedDL: "Downloading",
	stalledDL: "Download stalled",
	queuedDL: "Queued download",
	metaDL: "Downloading metadata",
	allocating: "Allocating",
	checkingDL: "Checking download",
	uploading: "Uploading",
	forcedUP: "Uploading",
	stalledUP: "Upload stalled",
	queuedUP: "Queued upload",
	checkingUP: "Checking upload",
	pausedDL: "Paused download",
	pausedUP: "Paused upload",
	moving: "Moving",
	unknown: "Unknown state",
};

const DOWNLOAD_STATES = new Set([
	"downloading",
	"forcedDL",
	"stalledDL",
	"metaDL",
	"allocating",
]);
const UPLOAD_STATES = new Set(["uploading", "forcedUP", "stalledUP"]);

function stateLabel(state: string): string {
	return (
		STATE_LABELS[state] ??
		state
			.replace(/([a-z])([A-Z])/g, "$1 $2")
			.replace(/^./, (char) => char.toUpperCase())
	);
}

function fallbackDirectionCount(
	byState: Record<string, number> | undefined,
	states: Set<string>,
): number {
	return Object.entries(byState ?? {}).reduce(
		(total, [state, count]) => total + (states.has(state) ? count : 0),
		0,
	);
}

export function QbittorrentTotalsWidget({
	widget,
	refreshIntervalMs,
	description,
}: Props) {
	const { data, isLoading } = useWidgetData(widget.id, refreshIntervalMs);
	const payload = data?.data as TotalsPayload | undefined;
	const byState = payload?.by_state ?? {};
	const downloading =
		payload?.by_direction?.downloading ??
		fallbackDirectionCount(byState, DOWNLOAD_STATES);
	const uploading =
		payload?.by_direction?.uploading ??
		fallbackDirectionCount(byState, UPLOAD_STATES);
	const stateEntries = Object.entries(byState).sort(
		([stateA, countA], [stateB, countB]) =>
			countB - countA || stateLabel(stateA).localeCompare(stateLabel(stateB)),
	);

	return (
		<SectionCard title={widget.title} description={description}>
			{isLoading && !data ? (
				<Skeleton className="h-32 w-full" />
			) : data?.error ? (
				<Alert variant="destructive">
					<AlertDescription>{data.error}</AlertDescription>
				</Alert>
			) : payload ? (
				<div className="space-y-4">
					<div className="grid grid-cols-3 gap-2">
						<div className="rounded-md border p-3">
							<div className="text-2xl font-semibold">{payload.total ?? 0}</div>
							<div className="text-xs text-muted-foreground">
								Total torrents
							</div>
						</div>
						<div className="rounded-md border p-3">
							<div className="text-2xl font-semibold">{downloading}</div>
							<div className="text-xs text-muted-foreground">Downloading</div>
						</div>
						<div className="rounded-md border p-3">
							<div className="text-2xl font-semibold">{uploading}</div>
							<div className="text-xs text-muted-foreground">Uploading</div>
						</div>
					</div>
					{stateEntries.length > 0 && (
						<div>
							<div className="mb-2 text-xs font-medium text-muted-foreground uppercase">
								Torrent states
							</div>
							<div className="grid gap-1.5 sm:grid-cols-2">
								{stateEntries.map(([state, count]) => (
									<div
										key={state}
										className="flex items-center justify-between rounded-md bg-muted/50 px-3 py-2 text-sm"
									>
										<span>{stateLabel(state)}</span>
										<span className="font-medium">{count}</span>
									</div>
								))}
							</div>
						</div>
					)}
				</div>
			) : (
				<div className="text-xs text-muted-foreground">
					No torrent data available.
				</div>
			)}
		</SectionCard>
	);
}
