import { useMemo, useState } from "react";
import { useNavigate, useSearchParams } from "react-router-dom";
import type { ColumnDef, RowSelectionState } from "@tanstack/react-table";

import { DataTable } from "@/components/ui/data-table";
import { Alert, AlertAction, AlertDescription } from "@/components/ui/alert";
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 { Label } from "@/components/ui/label";
import {
	Select,
	SelectContent,
	SelectItem,
	SelectTrigger,
	SelectValue,
} from "@/components/ui/select";
import { TabsTrigger } from "@/components/ui/tabs";
import {
	useDirectoryListing,
	useFfprobe,
	useJobTemplates,
	useRunJob,
} from "../hooks/useFiles";
import { usePersistentState } from "../hooks/usePersistentState";
import { useMonitoringSettings } from "../hooks/useSettings";
import { SectionCard } from "../components/SectionCard";
import { TabbedCard } from "../components/TabbedCard";

interface DisplayRow {
	id: string;
	type: string;
	name: string;
	ext: string;
	size: string;
	modified: string;
	path: string;
}

interface FfprobeStream {
	index?: number;
	codec_type?: string;
	codec_name?: string;
	codec_long_name?: string;
	profile?: string;
	width?: number;
	height?: number;
	bit_rate?: string | number;
	duration?: string | number;
	channels?: number;
	sample_rate?: string | number;
	channel_layout?: string;
	pix_fmt?: string;
	sample_aspect_ratio?: string;
	display_aspect_ratio?: string;
	field_order?: string;
	level?: number | string;
	color_range?: string;
	color_space?: string;
	color_transfer?: string;
	color_primaries?: string;
	tags?: Record<string, string>;
}

interface FfprobeFormat {
	filename?: string;
	format_name?: string;
	format_long_name?: string;
	duration?: string | number;
	size?: string | number;
	bit_rate?: string | number;
	tags?: Record<string, string>;
}

interface FfprobeData {
	format?: FfprobeFormat;
	streams?: FfprobeStream[];
}

function formatSize(bytes: number): string {
	if (bytes === 0) return "-";
	const units = ["B", "KB", "MB", "GB", "TB"];
	let value = bytes;
	let unitIdx = 0;
	while (value >= 1000 && unitIdx < units.length - 1) {
		value /= 1000;
		unitIdx++;
	}
	return `${value.toFixed(1)} ${units[unitIdx]}`;
}

function formatTime(epoch: number): string {
	if (!epoch) return "";
	return new Date(epoch * 1000).toLocaleString();
}

function humanBytes(value: string | number | undefined): string {
	if (value === undefined || value === null || value === "") return "-";
	const bytes = typeof value === "string" ? Number(value) : value;
	if (!Number.isFinite(bytes)) return "-";
	return formatSize(bytes);
}

function humanRate(value: string | number | undefined): string {
	if (value === undefined || value === null || value === "") return "-";
	const rate = typeof value === "string" ? Number(value) : value;
	if (!Number.isFinite(rate)) return "-";
	const units = ["bps", "Kbps", "Mbps", "Gbps"];
	let v = rate;
	let unitIdx = 0;
	while (v >= 1000 && unitIdx < units.length - 1) {
		v /= 1000;
		unitIdx++;
	}
	return `${v.toFixed(1)} ${units[unitIdx]}`;
}

function humanDuration(value: string | number | undefined): string {
	if (value === undefined || value === null || value === "") return "-";
	const seconds = typeof value === "string" ? Number(value) : value;
	if (!Number.isFinite(seconds)) return "-";
	const total = Math.max(0, Math.round(seconds));
	const hours = Math.floor(total / 3600);
	const minutes = Math.floor((total % 3600) / 60);
	const secs = total % 60;
	if (hours > 0)
		return `${hours}:${String(minutes).padStart(2, "0")}:${String(secs).padStart(2, "0")}`;
	return `${minutes}:${String(secs).padStart(2, "0")}`;
}

function fieldLabel(_key: string, value: string | number | undefined): string {
	if (value === undefined || value === null || value === "") return "-";
	return String(value);
}

function isVideoFile(name: string): boolean {
	const exts = [
		".mkv",
		".mp4",
		".avi",
		".m4v",
		".ts",
		".wmv",
		".mov",
		".flv",
		".webm",
	];
	return exts.some((ext) => name.toLowerCase().endsWith(ext));
}

// Design §3.2: referentially-stable column defs (a new array each render would
// destabilize the TanStack table instance and drop controlled selection).
// Visibility-only: no sorting, no sizing/resizing (design §3.3).
const fileColumns: ColumnDef<DisplayRow>[] = [
	{
		accessorKey: "type",
		header: () => "Type",
		cell: ({ row }) => (
			<span className="text-muted-foreground">{row.original.type}</span>
		),
	},
	{
		accessorKey: "name",
		header: () => "Name",
		cell: ({ row }) => <span className="font-medium">{row.original.name}</span>,
	},
	{
		accessorKey: "ext",
		header: () => "Ext",
		cell: ({ row }) => row.original.ext,
	},
	{
		accessorKey: "size",
		header: () => "Size",
		cell: ({ row }) => row.original.size,
	},
	{
		accessorKey: "modified",
		header: () => "Modified",
		cell: ({ row }) => row.original.modified,
	},
];

const FILE_BROWSER_STATE_KEY = "manage.files.browserState";

type FileBrowserState = {
	currentDir: string;
	pathInput: string;
	selectedPath: string | null;
	selectedJob: string;
};

function defaultFileBrowserState(): FileBrowserState {
	return {
		currentDir: "/",
		pathInput: "/",
		selectedPath: null,
		selectedJob: "",
	};
}

function FfprobeChip({
	children,
	variant = "outline",
}: {
	children: React.ReactNode;
	variant?: "outline" | "secondary" | "warning" | "default";
}) {
	return <Badge variant={variant}>{children}</Badge>;
}

function StreamBlock({ children }: { children: React.ReactNode }) {
	return <div className="rounded-md border p-3">{children}</div>;
}

function FfprobeDetails({ path, data }: { path: string; data: FfprobeData }) {
	const format = data.format ?? {};
	const streams = data.streams ?? [];
	const videoStreams = streams.filter(
		(stream) => stream.codec_type === "video",
	);
	const audioStreams = streams.filter(
		(stream) => stream.codec_type === "audio",
	);
	const subtitleStreams = streams.filter(
		(stream) => stream.codec_type === "subtitle",
	);

	return (
		<div className="flex flex-col gap-4">
			<div>
				<div className="text-base font-semibold">ffprobe details</div>
				<div className="text-xs text-muted-foreground">{path}</div>
			</div>

			<Card>
				<CardContent className="flex flex-col gap-3">
					<div className="text-sm font-semibold">Container / format</div>
					<div className="grid grid-cols-1 gap-3 md:grid-cols-2">
						<div className="text-sm space-y-0.5">
							<div>
								<span className="font-semibold">Format:</span>{" "}
								{fieldLabel("format", format.format_name)}
							</div>
							<div>
								<span className="font-semibold">Long name:</span>{" "}
								{fieldLabel("format_long_name", format.format_long_name)}
							</div>
							<div>
								<span className="font-semibold">Duration:</span>{" "}
								{humanDuration(format.duration)}
							</div>
						</div>
						<div className="text-sm space-y-0.5">
							<div>
								<span className="font-semibold">Size:</span>{" "}
								{humanBytes(format.size)}
							</div>
							<div>
								<span className="font-semibold">Bitrate:</span>{" "}
								{humanRate(format.bit_rate)}
							</div>
							<div>
								<span className="font-semibold">Filename:</span>{" "}
								{fieldLabel("filename", format.filename)}
							</div>
						</div>
					</div>
				</CardContent>
			</Card>

			<Card>
				<CardContent className="flex flex-col gap-3">
					<div className="text-sm font-semibold">Streams</div>

					{videoStreams.length > 0 && (
						<div>
							<div className="text-xs text-muted-foreground">Video streams</div>
							<div className="mt-1.5 flex flex-col gap-2">
								{videoStreams.map((stream, index) => {
									const isHdr =
										(stream.color_transfer ?? "")
											.toLowerCase()
											.includes("2084") ||
										(stream.color_transfer ?? "")
											.toLowerCase()
											.includes("b67") ||
										(stream.color_space ?? "")
											.toLowerCase()
											.includes("bt2020") ||
										(stream.color_primaries ?? "")
											.toLowerCase()
											.includes("bt2020");
									return (
										<StreamBlock key={`video-${stream.index ?? index}`}>
											<div className="flex flex-row flex-wrap items-center gap-1.5">
												<FfprobeChip>#{stream.index ?? index}</FfprobeChip>
												<FfprobeChip variant="default">
													{stream.codec_type ?? "video"}
												</FfprobeChip>
												<FfprobeChip variant="outline">
													{stream.codec_name ?? "unknown codec"}
												</FfprobeChip>
												{stream.codec_long_name && (
													<FfprobeChip variant="outline">
														{stream.codec_long_name}
													</FfprobeChip>
												)}
												{stream.profile && (
													<FfprobeChip variant="outline">
														{stream.profile}
													</FfprobeChip>
												)}
												{stream.bit_rate && (
													<FfprobeChip variant="outline">
														{humanRate(stream.bit_rate)}
													</FfprobeChip>
												)}
												{stream.duration && (
													<FfprobeChip variant="outline">
														{humanDuration(stream.duration)}
													</FfprobeChip>
												)}
												{stream.width && stream.height && (
													<FfprobeChip variant="outline">
														{`${stream.width}×${stream.height}`}
													</FfprobeChip>
												)}
												{stream.pix_fmt && (
													<FfprobeChip variant="outline">
														{stream.pix_fmt}
													</FfprobeChip>
												)}
												{stream.display_aspect_ratio && (
													<FfprobeChip variant="outline">
														{`DAR ${stream.display_aspect_ratio}`}
													</FfprobeChip>
												)}
												{stream.sample_aspect_ratio && (
													<FfprobeChip variant="outline">
														{`SAR ${stream.sample_aspect_ratio}`}
													</FfprobeChip>
												)}
												{stream.level !== undefined &&
													stream.level !== null && (
														<FfprobeChip variant="outline">{`L${stream.level}`}</FfprobeChip>
													)}
												{stream.field_order &&
													stream.field_order !== "unknown" && (
														<FfprobeChip variant="outline">
															{stream.field_order}
														</FfprobeChip>
													)}
												{(stream.color_range ||
													stream.color_space ||
													stream.color_transfer ||
													stream.color_primaries) && (
													<FfprobeChip variant={isHdr ? "warning" : "outline"}>
														{[
															stream.color_range,
															stream.color_space,
															stream.color_transfer,
															stream.color_primaries,
														]
															.filter(Boolean)
															.join(" / ")}
													</FfprobeChip>
												)}
											</div>
											<div className="mt-1.5 text-sm">
												{stream.tags?.language
													? `Language: ${stream.tags.language}. `
													: ""}
												{stream.tags?.title
													? `Title: ${stream.tags.title}.`
													: ""}
											</div>
										</StreamBlock>
									);
								})}
							</div>
						</div>
					)}

					{audioStreams.length > 0 && (
						<div>
							<div className="text-xs text-muted-foreground">Audio streams</div>
							<div className="mt-1.5 flex flex-col gap-2">
								{audioStreams.map((stream, index) => (
									<StreamBlock key={`audio-${stream.index ?? index}`}>
										<div className="flex flex-row flex-wrap items-center gap-1.5">
											<FfprobeChip>#{stream.index ?? index}</FfprobeChip>
											<FfprobeChip variant="secondary">
												{stream.codec_type ?? "audio"}
											</FfprobeChip>
											<FfprobeChip variant="outline">
												{stream.codec_name ?? "unknown codec"}
											</FfprobeChip>
											{stream.channels && (
												<FfprobeChip variant="outline">{`${stream.channels} ch`}</FfprobeChip>
											)}
											{stream.sample_rate && (
												<FfprobeChip variant="outline">{`${stream.sample_rate} Hz`}</FfprobeChip>
											)}
											{stream.bit_rate && (
												<FfprobeChip variant="outline">
													{humanRate(stream.bit_rate)}
												</FfprobeChip>
											)}
											{stream.duration && (
												<FfprobeChip variant="outline">
													{humanDuration(stream.duration)}
												</FfprobeChip>
											)}
										</div>
										<div className="mt-1.5 text-sm">
											{stream.codec_long_name
												? `${stream.codec_long_name}. `
												: ""}
											{stream.channel_layout
												? `Layout: ${stream.channel_layout}. `
												: ""}
											{stream.tags?.language
												? `Language: ${stream.tags.language}. `
												: ""}
											{stream.tags?.title ? `Title: ${stream.tags.title}.` : ""}
										</div>
									</StreamBlock>
								))}
							</div>
						</div>
					)}

					{subtitleStreams.length > 0 && (
						<div>
							<div className="text-xs text-muted-foreground">
								Subtitle streams
							</div>
							<div className="mt-1.5 flex flex-col gap-2">
								{subtitleStreams.map((stream, index) => (
									<StreamBlock key={`subtitle-${stream.index ?? index}`}>
										<div className="flex flex-row flex-wrap items-center gap-1.5">
											<FfprobeChip>#{stream.index ?? index}</FfprobeChip>
											<FfprobeChip variant="secondary">
												{stream.codec_type ?? "subtitle"}
											</FfprobeChip>
											<FfprobeChip variant="outline">
												{stream.codec_name ?? "unknown codec"}
											</FfprobeChip>
											{stream.tags?.language && (
												<FfprobeChip variant="outline">
													{stream.tags.language}
												</FfprobeChip>
											)}
											{stream.tags?.title && (
												<FfprobeChip variant="outline">
													{stream.tags.title}
												</FfprobeChip>
											)}
										</div>
									</StreamBlock>
								))}
							</div>
						</div>
					)}

					{streams.length === 0 && (
						<div className="text-sm text-muted-foreground">
							No streams found.
						</div>
					)}
				</CardContent>
			</Card>

			{Object.keys(format.tags ?? {}).length > 0 && (
				<Card>
					<CardContent className="flex flex-col gap-2">
						<div className="text-sm font-semibold">Tags</div>
						<div className="flex flex-row flex-wrap gap-1.5">
							{Object.entries(format.tags ?? {}).map(([key, value]) => (
								<FfprobeChip key={key} variant="outline">
									{`${key}: ${value}`}
								</FfprobeChip>
							))}
						</div>
					</CardContent>
				</Card>
			)}
		</div>
	);
}

function InfoAlert({ children }: { children: React.ReactNode }) {
	return (
		<Alert>
			<AlertDescription>{children}</AlertDescription>
		</Alert>
	);
}

export function FileBrowser() {
	const [searchParams, setSearchParams] = useSearchParams();
	const [columnVisibility, setColumnVisibility] = useState<
		Record<string, boolean>
	>({});
	const { data: machines } = useMonitoringSettings();
	const fileMachines = useMemo(
		() =>
			(machines ?? []).filter(
				(machine) =>
					machine.enabled &&
					(machine.services.includes("files") ||
						machine.services.includes("monitoring")),
			),
		[machines],
	);
	const initialRequestedPath = searchParams.get("path");
	const initialMachineId =
		searchParams.get("machine_id") || fileMachines[0]?.id || "";
	const [browserState, setBrowserState] = usePersistentState<FileBrowserState>(
		FILE_BROWSER_STATE_KEY,
		() => {
			const requestedPath = initialRequestedPath ?? "/";
			const selectedPath =
				requestedPath !== "/" &&
				(isVideoFile(requestedPath) || requestedPath.includes("."))
					? requestedPath.replace(/\/+$/, "")
					: null;
			const currentDir = selectedPath
				? selectedPath.replace(/\/[^/]+$/, "") || "/"
				: requestedPath.replace(/\/+$/, "") || "/";
			return {
				...defaultFileBrowserState(),
				currentDir,
				pathInput: requestedPath || currentDir,
				selectedPath,
			};
		},
	);
	const { currentDir, pathInput, selectedPath, selectedJob } = browserState;
	const selectedMachineId = searchParams.get("machine_id") || initialMachineId;
	const navigateToSettings = useNavigate();
	const updateBrowserState = (patch: Partial<FileBrowserState>) =>
		setBrowserState((current) => ({ ...current, ...patch }));

	const {
		data: listing,
		isLoading,
		error,
		refetch,
	} = useDirectoryListing(currentDir, selectedMachineId || undefined);
	const {
		data: ffprobeData,
		isLoading: ffprobeLoading,
		error: ffprobeError,
	} = useFfprobe(
		selectedPath ?? "",
		!!selectedPath && isVideoFile(selectedPath),
		selectedMachineId || undefined,
	);
	const { data: templates } = useJobTemplates();
	const runJob = useRunJob(selectedMachineId || undefined);

	const navigate = (path: string) => {
		updateBrowserState({
			currentDir: path,
			pathInput: path,
			selectedPath: null,
		});
	};

	const setMachine = (machineId: string) => {
		setSearchParams(
			(current) => {
				const next = new URLSearchParams(current);
				if (machineId) next.set("machine_id", machineId);
				else next.delete("machine_id");
				return next;
			},
			{ replace: true },
		);
	};

	const handlePathSubmit = (e: React.KeyboardEvent) => {
		if (e.key === "Enter") navigate(pathInput || "/");
	};

	const rows: DisplayRow[] = [];
	if (currentDir !== "/") {
		const parent = currentDir.replace(/\/[^/]+\/?$/, "") || "/";
		rows.push({
			id: `up-${parent}`,
			type: "up",
			name: "..",
			ext: "",
			size: "-",
			modified: "",
			path: parent,
		});
	}
	if (listing) {
		for (const entry of listing.entries) {
			const kind = entry.type === "d" ? "dir" : "file";
			const ext = kind === "file" ? (entry.name.split(".").pop() ?? "") : "";
			const path = `${currentDir === "/" ? "" : currentDir}/${entry.name}`;
			rows.push({
				id: path,
				type: kind,
				name: entry.name,
				ext,
				size: kind === "dir" ? "-" : formatSize(entry.size),
				modified: formatTime(entry.mtime),
				path,
			});
		}
	}

	// Preserved row-click behavior (MUI DataGrid onRowClick): dir/up rows navigate;
	// file rows select the file for ffprobe preview (also feeds pathInput).
	const handleRowClick = (row: DisplayRow) => {
		if (row.type === "dir" || row.type === "up") {
			navigate(row.path);
			return;
		}
		updateBrowserState({
			selectedPath: row.path,
			currentDir,
			pathInput: row.path,
		});
	};

	// Single-select checkbox behavior (DataTable adds a selection column under
	// enableRowSelection): mirrors the row-click selection for file rows.
	const rowSelection: RowSelectionState = selectedPath
		? { [selectedPath]: true }
		: {};
	const handleSelectionChange = (
		updater:
			| RowSelectionState
			| ((prev: RowSelectionState) => RowSelectionState),
	) => {
		const next =
			typeof updater === "function" ? updater(rowSelection) : updater;
		const selectedIds = Object.keys(next).filter((id) => next[id]);
		const id = selectedIds[selectedIds.length - 1];
		if (!id) {
			updateBrowserState({ selectedPath: null });
			return;
		}
		const target = rows.find((row) => row.id === id);
		if (target && target.type === "file") {
			updateBrowserState({ selectedPath: target.path, pathInput: target.path });
		} else {
			updateBrowserState({ selectedPath: null });
		}
	};

	const selectedTemplate = templates?.find((t) => t.key === selectedJob);

	return (
		<div className="flex flex-col gap-4.5">
			<div className="flex flex-row flex-wrap items-center gap-2">
				<h2 className="text-xl font-semibold">File Browser</h2>
				<Badge variant="outline">
					{fileMachines.length
						? `${fileMachines.length} machine${fileMachines.length === 1 ? "" : "s"}`
						: "No file machines"}
				</Badge>
			</div>

			<TabbedCard
				value={fileMachines.length > 0 ? selectedMachineId : ""}
				onChange={setMachine}
				tabs={fileMachines.map((machine) => (
					<TabsTrigger key={machine.id} value={machine.id}>
						{`${machine.name} · ${machine.mode}`}
					</TabsTrigger>
				))}
			>
				{fileMachines.length > 0 ? (
					<div className="flex flex-col gap-4">
						<SectionCard
							title="Browser"
							description="Read-only listing with explicit open/select actions."
						>
							<div className="flex flex-col gap-3">
								<div className="flex flex-col gap-2 md:flex-row">
									<div className="flex flex-1 flex-col gap-1">
										<Label htmlFor="remote-path">Remote path</Label>
										<Input
											id="remote-path"
											value={pathInput}
											onChange={(e) =>
												updateBrowserState({ pathInput: e.target.value })
											}
											onKeyDown={handlePathSubmit}
										/>
									</div>
									<div className="flex flex-col gap-2 md:flex-row md:items-end">
										<Button
											variant="outline"
											className="w-full md:w-auto"
											onClick={() => navigate(pathInput || "/")}
										>
											Open
										</Button>
										<Button
											variant="outline"
											className="w-full md:w-auto"
											onClick={() => refetch()}
										>
											Refresh
										</Button>
									</div>
								</div>
								<div className="text-xs text-muted-foreground">
									{`Current: ${currentDir} `}
									{selectedPath ? `| Selected: ${selectedPath} ` : ""}
									{listing ? `| Entries: ${listing.count}` : ""}
								</div>
								{error && (
									<Alert variant="destructive">
										<AlertDescription>{String(error)}</AlertDescription>
									</Alert>
								)}
								<div className="rounded-lg border bg-card">
									<DataTable
										columns={fileColumns}
										data={rows}
										getRowId={(row) => row.id}
										enableRowSelection
										rowSelection={rowSelection}
										onRowSelectionChange={handleSelectionChange}
										onRowClick={handleRowClick}
										enableColumnVisibilityToggle
										columnVisibility={columnVisibility}
										onColumnVisibilityChange={setColumnVisibility}
										emptyMessage={
											isLoading
												? "Loading directory..."
												: "This directory is empty."
										}
									/>
								</div>
							</div>
						</SectionCard>

						<SectionCard
							title="Media info"
							description="ffprobe metadata for the selected media file."
						>
							{selectedPath ? (
								isVideoFile(selectedPath) ? (
									ffprobeError ? (
										<Alert variant="destructive">
											<AlertDescription>
												{String(ffprobeError)}
											</AlertDescription>
										</Alert>
									) : ffprobeLoading && !ffprobeData ? (
										<InfoAlert>Loading ffprobe data...</InfoAlert>
									) : ffprobeData ? (
										<FfprobeDetails
											path={selectedPath}
											data={ffprobeData as FfprobeData}
										/>
									) : (
										<InfoAlert>No ffprobe data available.</InfoAlert>
									)
								) : (
									<InfoAlert>
										Select a video file to view ffprobe details.
									</InfoAlert>
								)
							) : (
								<InfoAlert>
									Select a file in Browser to view ffprobe details.
								</InfoAlert>
							)}
						</SectionCard>

						<SectionCard
							title="Jobs"
							description="Run predefined safe jobs against the selected file."
						>
							{selectedPath && templates && templates.length > 0 ? (
								<div className="flex flex-col gap-3">
									<div className="grid grid-cols-1 gap-3 md:grid-cols-4">
										<div className="flex flex-col gap-1.5">
											<Label htmlFor="job-template">Job template</Label>
											<Select
												value={selectedJob}
												onValueChange={(value) =>
													updateBrowserState({ selectedJob: value })
												}
											>
												<SelectTrigger id="job-template" className="w-full">
													<SelectValue placeholder="Select a job" />
												</SelectTrigger>
												<SelectContent>
													{templates.map((tpl) => (
														<SelectItem key={tpl.key} value={tpl.key}>
															{tpl.name}
														</SelectItem>
													))}
												</SelectContent>
											</Select>
										</div>
										<div className="flex flex-col gap-2 md:col-span-3 md:flex-row md:items-end">
											<Button
												disabled={!selectedJob || runJob.isPending}
												onClick={() =>
													runJob.mutate({
														jobKey: selectedJob,
														path: selectedPath,
													})
												}
											>
												Run job
											</Button>
											{selectedTemplate && (
												<div className="self-center text-sm text-muted-foreground">
													{selectedTemplate.description}
												</div>
											)}
										</div>
									</div>
									{runJob.data && (
										<pre className="max-h-[260px] overflow-auto rounded-md bg-muted p-3 text-xs">
											{`Exit: ${runJob.data.exit_status}`}
											{"\n"}
											{runJob.data.stdout}
											{runJob.data.stderr && `\nSTDERR: ${runJob.data.stderr}`}
										</pre>
									)}
								</div>
							) : (
								<InfoAlert>Select a file in Browser to run jobs.</InfoAlert>
							)}
						</SectionCard>
					</div>
				) : (
					<Alert>
						<AlertDescription>
							No file-capable machines are configured yet.
						</AlertDescription>
						<AlertAction>
							<Button
								variant="outline"
								size="sm"
								onClick={() => navigateToSettings("/settings")}
							>
								Open Settings
							</Button>
						</AlertAction>
					</Alert>
				)}
			</TabbedCard>
		</div>
	);
}
