/**
 * FilesTab — operational content for the ssh_tasks service page.
 *
 * Lifted from the old top-level `pages/FileBrowser.impl.tsx`. The machine
 * selector and `useMonitoringSettings` are removed; the active ssh_tasks
 * instance id (from the `instance` prop) replaces the machine_id. The initial
 * path is read from `?path=` search param for deep-link support (resolves the
 * MediaTab row-click navigation from slice 5). Everything else — directory
 * listing, path bar, ffprobe preview, job execution — is preserved.
 */
import { useState } from "react";
import { useSearchParams } from "react-router-dom";
import type { ColumnDef, RowSelectionState } from "@tanstack/react-table";

import { DataTable } from "@/components/ui/data-table";
import {
	MobileCardRow,
	type MobileCardField,
} from "@/components/ui/mobile-card";
import { Alert, 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 {
	useDirectoryListing,
	useFfprobe,
	useJobTemplates,
	useRunJob,
} from "../../hooks/useFiles";
import { usePersistentState } from "../../hooks/usePersistentState";
import { SectionCard } from "../../components/SectionCard";
import type { ServiceInstance } from "../../types";
import { useIsMobile } from "../../hooks/useIsMobile";

// Mobile card fields (mobile-parity pattern).
const fileCardFields: MobileCardField<DisplayRow>[] = [
	{ key: "name", label: "Name", render: (r) => r.name, primary: true },
	{ key: "type", label: "Type", render: (r) => r.type },
	{ key: "size", label: "Size", render: (r) => r.size || "-" },
	{ key: "modified", label: "Modified", render: (r) => r.modified || "-" },
];

// --- Types (lifted verbatim) ---

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[];
}

// --- Helpers (lifted verbatim) ---

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));
}

// --- Column defs (lifted verbatim) ---

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,
	},
];

// --- State + helpers (lifted) ---

const FILE_TAB_STATE_KEY = "manage.files.tabState";

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

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

// --- Ffprobe rendering (lifted verbatim) ---

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((s) => s.codec_type === "video");
	const audioStreams = streams.filter((s) => s.codec_type === "audio");
	const subtitleStreams = streams.filter((s) => s.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>
	);
}

// --- Component ---

export function FilesTab({ instance }: { instance: ServiceInstance }) {
	const isMobile = useIsMobile();
	const machineId = instance.id;
	const [searchParams] = useSearchParams();
	const requestedPath = searchParams.get("path");
	const [columnVisibility, setColumnVisibility] = useState<
		Record<string, boolean>
	>({});
	const [browserState, setBrowserState] = usePersistentState<FileBrowserState>(
		`${FILE_TAB_STATE_KEY}.${instance.id}`,
		() => {
			const path = requestedPath ?? "/";
			const selectedPath =
				path !== "/" && (isVideoFile(path) || path.includes("."))
					? path.replace(/\/+$/, "")
					: null;
			const currentDir = selectedPath
				? selectedPath.replace(/\/[^/]+$/, "") || "/"
				: path.replace(/\/+$/, "") || "/";
			return {
				...defaultFileBrowserState(),
				currentDir,
				pathInput: path || currentDir,
				selectedPath,
			};
		},
	);
	const { currentDir, pathInput, selectedPath, selectedJob } = browserState;
	const updateBrowserState = (patch: Partial<FileBrowserState>) =>
		setBrowserState((current) => ({ ...current, ...patch }));

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

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

	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,
			});
		}
	}

	const handleRowClick = (row: DisplayRow) => {
		if (row.type === "dir" || row.type === "up") {
			navigate(row.path);
			return;
		}
		updateBrowserState({
			selectedPath: row.path,
			currentDir,
			pathInput: row.path,
		});
	};

	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">
			<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">
					{isMobile ? (
						<div className="p-4">
							<MobileCardRow
								rows={rows}
								fields={fileCardFields}
								getRowId={(row) => row.id}
								onRowClick={handleRowClick}
							/>
						</div>
					) : (
						<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 ? (
							<Alert>
								<AlertDescription>Loading ffprobe data...</AlertDescription>
							</Alert>
						) : ffprobeData ? (
							<FfprobeDetails
								path={selectedPath}
								data={ffprobeData as FfprobeData}
							/>
						) : (
							<Alert>
								<AlertDescription>No ffprobe data available.</AlertDescription>
							</Alert>
						)
					) : (
						<Alert>
							<AlertDescription>
								Select a video file to view ffprobe details.
							</AlertDescription>
						</Alert>
					)
				) : (
					<Alert>
						<AlertDescription>
							Select a file in Browser to view ffprobe details.
						</AlertDescription>
					</Alert>
				)}
			</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>
				) : (
					<Alert>
						<AlertDescription>
							Select a file in Browser to run jobs.
						</AlertDescription>
					</Alert>
				)}
			</SectionCard>
		</div>
	);
}
