import type { ReactNode } from "react";
import { useMemo, useState } from "react";
import { useSearchParams } from "react-router-dom";
import type {
	MonitoringMachine,
	MonitoringMachineInput,
	SSHKey,
	SSHKeyInput,
} from "../types";
import {
	useDeleteMonitoringMachine,
	useDeleteSSHKey,
	useGenerateSSHKey,
	useMonitoringSettings,
	useResetLocalDatabase,
	useSSHKeys,
	useSaveMonitoringMachine,
	useSaveSSHKey,
	useTestMonitoringMachineSSH,
} from "../hooks/useSettings";
import { useIsMobile } from "../hooks/useIsMobile";
import { CreateServiceDialog, DashboardManagementCard } from "./ServicesPage";
import { SheetForm } from "@/components/ui/sheet-form";
import { DialogFooter } from "../components/DialogFooter";
import { HoverEditButton } from "../components/HoverEditButton";
import { SectionCard } from "../components/SectionCard";
import { SelectionRailCard } from "../components/SelectionRailCard";
import { TabbedCard } from "../components/TabbedCard";
import { ConfirmDialog } from "../components/ConfirmDialog";
import { cn } from "@/lib/utils";
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 { Checkbox } from "@/components/ui/checkbox";
import {
	Dialog,
	DialogContent,
	DialogDescription,
	DialogHeader,
	DialogTitle,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
	Select,
	SelectContent,
	SelectItem,
	SelectTrigger,
	SelectValue,
} from "@/components/ui/select";
import { Switch } from "@/components/ui/switch";
import { TabsTrigger } from "@/components/ui/tabs";
import { Textarea } from "@/components/ui/textarea";
import {
	useDeleteServiceInstance,
	useSaveServiceInstance,
	useServiceInstances,
	useServiceTypes,
	useTestServiceInstance,
} from "../hooks/useServices";
import { ServiceTestPanel } from "../components/ServiceTestPanel";
import type {
	ServiceInstance,
	ServiceInstanceInput,
	ServiceTestResult,
	ServiceTypeInfo,
} from "../types";

const SERVICE_OPTIONS = [
	{ value: "monitoring", label: "Monitoring" },
	{ value: "files", label: "Files" },
	{ value: "nextcloud", label: "Nextcloud" },
];

// Radix Select disallows empty-string item values, so the "no selection" option
// maps to this sentinel and converts back to "" at the draft boundary.
const NONE = "__none__";

type SettingsTab =
	| "machines"
	| "ssh-keys"
	| "services"
	| "dashboards"
	| "danger";

/** Small labeled-field wrapper replacing the MUI `<TextField label>` shell. */
function FormField({
	label,
	htmlFor,
	helperText,
	children,
}: {
	label: string;
	htmlFor?: string;
	helperText?: string;
	children: ReactNode;
}) {
	return (
		<div className="flex flex-col">
			<Label htmlFor={htmlFor} className="mb-1">
				{label}
			</Label>
			{children}
			{helperText ? (
				<p className="mt-1 text-xs text-muted-foreground">{helperText}</p>
			) : null}
		</div>
	);
}

/** Overline section label (replaces MUI `Typography variant="overline"`). */
function SectionLabel({
	title,
	description,
}: {
	title: string;
	description: string;
}) {
	return (
		<div className="pt-1">
			<p className="text-[0.7rem] leading-tight font-medium tracking-wide text-muted-foreground uppercase">
				{title}
			</p>
			<p className="text-xs text-muted-foreground">{description}</p>
		</div>
	);
}

function emptyMachine(
	mode: MonitoringMachineInput["mode"] = "local",
): MonitoringMachineInput {
	return {
		id: null,
		name: mode === "local" ? "This machine" : "",
		mode,
		enabled: true,
		services: mode === "local" ? ["monitoring", "files"] : [],
		host: "",
		port: 22,
		username: "",
		key_directory: "",
		key_name: "",
		ssh_key_id: "",
		ssh_private_key: "",
		ssh_private_key_passphrase: "",
		password: "",
		notes: "",
	};
}

/**
 * Dirty check for the machine editor SheetForm guard (spec R4.5).
 * Pragmatic field-by-field comparison of the user-editable fields. In create
 * mode (editingMachine is null) the form is always dirty.
 */
function isMachineDraftDirty(
	draft: MonitoringMachineInput,
	editingMachine: MonitoringMachine | null,
): boolean {
	if (!editingMachine) return true;
	return (
		draft.name !== editingMachine.name ||
		draft.host !== editingMachine.host ||
		draft.mode !== editingMachine.mode ||
		draft.port !== editingMachine.port ||
		draft.username !== editingMachine.username ||
		draft.ssh_key_id !== editingMachine.ssh_key_id ||
		draft.enabled !== editingMachine.enabled ||
		draft.notes !== editingMachine.notes ||
		JSON.stringify([...draft.services].sort()) !==
			JSON.stringify([...editingMachine.services].sort())
	);
}

function MachineEditor({
	title,
	hint,
	machine,
	sshKeys,
	editingMachine,
	onChange,
	onValidateSSH,
	isValidatingSSH,
	sshValidationMessage,
	sshValidationError,
	sshValidationStatus,
}: {
	title: string;
	hint?: string;
	machine: MonitoringMachineInput;
	sshKeys: SSHKey[];
	editingMachine?: MonitoringMachine | null;
	onChange: (
		draft:
			| MonitoringMachineInput
			| ((current: MonitoringMachineInput) => MonitoringMachineInput),
	) => void;
	onValidateSSH: () => void;
	isValidatingSSH: boolean;
	sshValidationMessage: string;
	sshValidationError: string;
	sshValidationStatus: string;
}) {
	const draft = machine;
	const setDraft = onChange;
	const isLocal = draft.mode === "local";
	const selectedSSHKey = sshKeys.find((key) => key.id === draft.ssh_key_id);
	const enabledServices = draft.services.length;
	const placeholderIfSet = (isSet: boolean | undefined) =>
		isSet ? "Set, not shown" : undefined;
	return (
		<Card>
			<CardContent className="flex flex-col gap-4 p-3">
				<div className="flex flex-wrap items-center justify-between gap-2">
					<div>
						<p className="text-sm font-semibold">{title}</p>
						{hint ? (
							<p className="text-xs text-muted-foreground">{hint}</p>
						) : null}
					</div>
					<div className="flex flex-row flex-wrap items-center gap-1">
						<Badge variant="outline">{draft.mode}</Badge>
						<Badge variant="outline">
							{draft.enabled ? "enabled" : "disabled"}
						</Badge>
						<Badge variant="outline">{`${enabledServices} services`}</Badge>
					</div>
				</div>
				<div className="grid grid-cols-12 gap-2">
					<div className="col-span-12">
						<SectionLabel
							title="General"
							description="Name, mode, enabled state, and service roles."
						/>
					</div>
					<div className="col-span-12 md:col-span-6">
						<FormField label="Name" htmlFor="machine-name">
							<Input
								id="machine-name"
								value={draft.name}
								onChange={(e) =>
									setDraft((current) => ({ ...current, name: e.target.value }))
								}
							/>
						</FormField>
					</div>
					<div className="col-span-12 md:col-span-3">
						{editingMachine ? (
							<FormField label="Mode">
								<Input value={draft.mode} disabled />
							</FormField>
						) : (
							<FormField label="Mode">
								<Select
									value={draft.mode}
									onValueChange={(value) => {
										const newMode = value as MonitoringMachineInput["mode"];
										setDraft((current) => ({
											...emptyMachine(newMode),
											id: current.id,
										}));
									}}
								>
									<SelectTrigger className="w-full" size="sm">
										<SelectValue />
									</SelectTrigger>
									<SelectContent>
										<SelectItem value="local">Local</SelectItem>
										<SelectItem value="ssh">SSH</SelectItem>
									</SelectContent>
								</Select>
							</FormField>
						)}
					</div>
					<div className="col-span-12 md:col-span-3">
						<div className="flex items-center gap-2">
							<Switch
								id="machine-enabled"
								className="mobile-touch-target"
								checked={draft.enabled}
								onCheckedChange={(checked) =>
									setDraft((current) => ({ ...current, enabled: checked }))
								}
							/>
							<Label htmlFor="machine-enabled">
								{draft.enabled ? "Enabled" : "Disabled"}
							</Label>
						</div>
					</div>
					<div className="col-span-12">
						<div className="flex flex-row flex-wrap items-center gap-1">
							{SERVICE_OPTIONS.map((option) => {
								const checked = draft.services.includes(option.value);
								return (
									<button
										key={option.value}
										type="button"
										onClick={() =>
											setDraft((current) => ({
												...current,
												services: checked
													? current.services.filter(
															(service) => service !== option.value,
														)
													: [...current.services, option.value],
											}))
										}
										className={cn(
											"inline-flex h-5 cursor-pointer items-center gap-1 rounded-full px-2 py-0.5 text-xs font-medium transition-colors",
											checked
												? "bg-primary text-primary-foreground"
												: "border border-border text-foreground hover:bg-muted",
										)}
									>
										{option.label}
									</button>
								);
							})}
						</div>
					</div>
					{!isLocal && (
						<>
							<div className="col-span-12">
								<SectionLabel
									title="Connection"
									description="SSH host, port, username, and credentials."
								/>
							</div>
							<div className="col-span-12 md:col-span-4">
								<FormField label="Host">
									<Input
										value={draft.host}
										onChange={(e) =>
											setDraft((current) => ({
												...current,
												host: e.target.value,
											}))
										}
									/>
								</FormField>
							</div>
							<div className="col-span-12 md:col-span-2">
								<FormField label="Port">
									<Input
										type="number"
										value={draft.port}
										onChange={(e) =>
											setDraft((current) => ({
												...current,
												port: Number(e.target.value || 22),
											}))
										}
									/>
								</FormField>
							</div>
							<div className="col-span-12 md:col-span-3">
								<FormField label="Username">
									<Input
										value={draft.username}
										onChange={(e) =>
											setDraft((current) => ({
												...current,
												username: e.target.value,
											}))
										}
									/>
								</FormField>
							</div>
							<div className="col-span-12 md:col-span-4">
								<FormField
									label="SSH key"
									helperText={
										sshKeys.length > 0
											? "Select a saved SSH key."
											: "No SSH keys are saved yet. Add one in the SSH Keys tab."
									}
								>
									<Select
										value={draft.ssh_key_id || NONE}
										onValueChange={(value) =>
											setDraft((current) => ({
												...current,
												ssh_key_id: value === NONE ? "" : value,
											}))
										}
									>
										<SelectTrigger className="w-full" size="sm">
											<SelectValue placeholder="No key selected" />
										</SelectTrigger>
										<SelectContent>
											<SelectItem value={NONE}>No key selected</SelectItem>
											{sshKeys.map((key) => (
												<SelectItem key={key.id} value={key.id}>
													{key.name}
												</SelectItem>
											))}
										</SelectContent>
									</Select>
								</FormField>
							</div>
							<div className="col-span-12 md:col-span-6">
								<FormField label="Password">
									<Input
										type="password"
										placeholder={placeholderIfSet(editingMachine?.password_set)}
										value={draft.password}
										onChange={(e) =>
											setDraft((current) => ({
												...current,
												password: e.target.value,
											}))
										}
									/>
								</FormField>
							</div>
						</>
					)}
					<div className="col-span-12">
						<SectionLabel
							title="Monitoring / Files"
							description="Enable monitoring and file browsing for this machine."
						/>
					</div>
					{isLocal && (
						<div className="col-span-12 md:col-span-6">
							<FormField label="Local hint">
								<Input value="Uses the API host directly" disabled />
							</FormField>
						</div>
					)}
					<div className="col-span-12">
						<SectionLabel
							title="Notes"
							description="Free-form administrator notes for this machine."
						/>
					</div>
					<div className="col-span-12">
						<FormField label="Notes">
							<Input
								value={draft.notes}
								onChange={(e) =>
									setDraft((current) => ({ ...current, notes: e.target.value }))
								}
							/>
						</FormField>
					</div>
				</div>
				{selectedSSHKey ? (
					<Alert>
						<AlertDescription>
							Selected key: {selectedSSHKey.name}
							{selectedSSHKey.fingerprint
								? ` · ${selectedSSHKey.fingerprint}`
								: ""}
						</AlertDescription>
					</Alert>
				) : !isLocal && sshKeys.length === 0 ? (
					<Alert>
						<AlertDescription>
							No SSH keys have been saved yet. Add one before configuring SSH
							machines.
						</AlertDescription>
					</Alert>
				) : draft.ssh_key_id ? (
					<Alert variant="destructive">
						<AlertDescription>
							The selected SSH key was not found.
						</AlertDescription>
					</Alert>
				) : null}
				{!isLocal && enabledServices === 0 && (
					<Alert>
						<AlertDescription>
							SSH machines usually need monitoring or files enabled.
						</AlertDescription>
					</Alert>
				)}
				{!isLocal && (
					<div className="flex flex-col gap-2">
						<Alert>
							<AlertDescription>
								Validate SSH before saving: this records the first trusted host
								key in the backend-managed known_hosts file, then checks SSH
								auth.
							</AlertDescription>
						</Alert>
						<div className="flex flex-row flex-wrap items-center gap-2">
							<Button
								className="mobile-touch-target"
								variant="outline"
								onClick={onValidateSSH}
								disabled={
									isValidatingSSH ||
									!draft.host.trim() ||
									!draft.username.trim()
								}
							>
								{isValidatingSSH
									? "Validating SSH..."
									: "Validate SSH + trust host"}
							</Button>
							<p className="text-xs text-muted-foreground">
								SSH status: {sshValidationStatus || "Not tested yet"}
							</p>
						</div>
						{sshValidationMessage && (
							<Alert>
								<AlertDescription>{sshValidationMessage}</AlertDescription>
							</Alert>
						)}
						{sshValidationError && (
							<Alert variant="destructive">
								<AlertDescription>{sshValidationError}</AlertDescription>
							</Alert>
						)}
					</div>
				)}
			</CardContent>
		</Card>
	);
}

function SSHKeyManager({
	sshKeys,
	selectedKeyId,
	onSelectKeyId,
}: {
	sshKeys: SSHKey[];
	selectedKeyId: string;
	onSelectKeyId: (id: string) => void;
}) {
	const saveKey = useSaveSSHKey();
	const generateKey = useGenerateSSHKey();
	const deleteKey = useDeleteSSHKey();
	const [draft, setDraft] = useState<SSHKeyInput>({
		id: null,
		name: "",
		private_key: "",
		public_key: "",
		fingerprint: "",
		passphrase: "",
		notes: "",
	});
	const selectedKey = useMemo(
		() => sshKeys.find((key) => key.id === selectedKeyId) ?? null,
		[sshKeys, selectedKeyId],
	);
	const editing = Boolean(draft.id);
	const clear = () => {
		setDraft({
			id: null,
			name: "",
			private_key: "",
			passphrase: "",
			public_key: "",
			fingerprint: "",
			notes: "",
		});
		onSelectKeyId("");
	};
	const loadKey = (key: SSHKey) => {
		onSelectKeyId(key.id);
		setDraft({
			id: key.id,
			name: key.name,
			private_key: "",
			passphrase: "",
			public_key: key.public_key,
			fingerprint: key.fingerprint,
			notes: key.notes,
		});
	};
	return (
		<div className="grid grid-cols-1 gap-4 md:grid-cols-[320px_minmax(0,1fr)]">
			<SelectionRailCard
				title="SSH keys"
				description="Select a key to see its details."
				minHeight={420}
				footer={
					<Button
						variant="outline"
						size="sm"
						className="mobile-touch-target w-full"
						onClick={() => {
							clear();
						}}
					>
						New key
					</Button>
				}
			>
				{sshKeys.length === 0 && (
					<div className="p-4 text-center">
						<p className="text-xs text-muted-foreground">
							No SSH keys saved yet.
						</p>
					</div>
				)}
				{sshKeys.map((key) => {
					const active = key.id === selectedKeyId;
					return (
						<div
							key={key.id}
							onClick={() => loadKey(key)}
							className={cn(
								"group grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] gap-2 border-t border-border px-3 py-2.5 group-hover:[&_.rail-edit]:opacity-100",
								active ? "bg-muted" : "bg-card hover:bg-muted/50",
							)}
						>
							<div className="min-w-0">
								<p className="truncate font-semibold">{key.name}</p>
								<p className="text-xs text-muted-foreground">
									{key.private_key_set ? "key saved" : "no key"} ·{" "}
									{key.usage_count} machine
									{key.usage_count === 1 ? "" : "s"}
								</p>
							</div>
							<HoverEditButton onClick={() => loadKey(key)} />
						</div>
					);
				})}
			</SelectionRailCard>
			<SectionCard
				title={selectedKey?.name || "No key selected"}
				description={
					selectedKey
						? `${selectedKey.fingerprint || "No fingerprint"}`
						: "Select a key on the left or create a new one."
				}
				action={
					selectedKey ? (
						<Badge variant="outline">{`${selectedKey.usage_count} machine${selectedKey.usage_count === 1 ? "" : "s"}`}</Badge>
					) : undefined
				}
			>
				<div className="flex flex-col gap-4">
					<div className="grid grid-cols-12 gap-2">
						<div className="col-span-12 md:col-span-4">
							<FormField label="Key name">
								<Input
									value={draft.name}
									onChange={(e) =>
										setDraft((current) => ({
											...current,
											name: e.target.value,
										}))
									}
								/>
							</FormField>
						</div>
						<div className="col-span-12 md:col-span-4">
							<FormField label="Passphrase" helperText="Optional">
								<Input
									type="password"
									value={draft.passphrase}
									onChange={(e) =>
										setDraft((current) => ({
											...current,
											passphrase: e.target.value,
										}))
									}
								/>
							</FormField>
						</div>
						<div className="col-span-12 md:col-span-4">
							<FormField label="Notes">
								<Input
									value={draft.notes}
									onChange={(e) =>
										setDraft((current) => ({
											...current,
											notes: e.target.value,
										}))
									}
								/>
							</FormField>
						</div>
						<div className="col-span-12">
							<FormField
								label="Private key"
								helperText={
									editing
										? "Leave blank to keep the existing private key."
										: "Paste the full key text here."
								}
							>
								<Textarea
									rows={6}
									value={draft.private_key}
									onChange={(e) =>
										setDraft((current) => ({
											...current,
											private_key: e.target.value,
										}))
									}
								/>
							</FormField>
						</div>
					</div>
					<div className="flex flex-row flex-wrap items-center gap-2">
						<Button
							className="mobile-touch-target"
							disabled={saveKey.isPending}
							onClick={async () => {
								await saveKey.mutateAsync(draft);
								clear();
							}}
						>
							{editing ? "Update key" : "Save key"}
						</Button>
						<Button
							className="mobile-touch-target"
							variant="outline"
							disabled={generateKey.isPending}
							onClick={async () => {
								const generated = await generateKey.mutateAsync({
									name:
										draft.name ||
										`ssh-key-${new Date().toISOString().slice(0, 10)}`,
									passphrase: draft.passphrase,
									notes: draft.notes,
								});
								setDraft((current) => ({
									...current,
									name: generated.name || current.name,
									private_key: generated.private_key,
									passphrase: generated.passphrase,
									public_key: generated.public_key,
									fingerprint: generated.fingerprint,
									notes: generated.notes,
								}));
							}}
						>
							{generateKey.isPending ? "Generating..." : "Generate key"}
						</Button>
						<Button
							variant="outline"
							onClick={clear}
							className="mobile-touch-target"
						>
							Clear
						</Button>
						{selectedKey && (
							<Button
								className="mobile-touch-target"
								variant="destructive"
								onClick={() => deleteKey.mutate(selectedKey.id)}
							>
								Delete
							</Button>
						)}
					</div>
					{saveKey.error && (
						<Alert variant="destructive">
							<AlertDescription>{String(saveKey.error)}</AlertDescription>
						</Alert>
					)}
					{selectedKey && (
						<div className="flex flex-col gap-2">
							<div className="rounded-lg border border-border px-3 py-2">
								<p className="text-xs text-muted-foreground">Fingerprint</p>
								<p className="break-all font-mono text-sm">
									{selectedKey.fingerprint || "Unavailable"}
								</p>
							</div>
							<div className="rounded-lg border border-border px-3 py-2">
								<p className="text-xs text-muted-foreground">Public key</p>
								<p className="break-all font-mono text-sm">
									{selectedKey.public_key || "Unavailable"}
								</p>
							</div>
						</div>
					)}
				</div>
			</SectionCard>
		</div>
	);
}

function ResetLocalDatabaseCard() {
	const resetDatabase = useResetLocalDatabase();
	const [open, setOpen] = useState(false);
	const [phrase, setPhrase] = useState("");
	const [ackSettings, setAckSettings] = useState(false);
	const [ackIndex, setAckIndex] = useState(false);
	const [ackIrreversible, setAckIrreversible] = useState(false);
	const canSubmit =
		phrase.trim().toLowerCase() === "reset local database" &&
		ackSettings &&
		ackIndex &&
		ackIrreversible;
	const close = () => {
		setOpen(false);
		setPhrase("");
		setAckSettings(false);
		setAckIndex(false);
		setAckIrreversible(false);
	};
	return (
		<>
			<Card>
				<CardContent className="flex flex-col gap-4 p-3">
					<div className="flex flex-row flex-wrap items-center gap-2">
						<p className="text-sm font-semibold">Danger zone</p>
						<Badge variant="destructive">Destructive</Badge>
					</div>
					<p className="text-xs text-muted-foreground">
						Reset the local SQLite settings/media index databases after
						acknowledging the data loss.
					</p>
					<Button
						variant="destructive"
						onClick={() => setOpen(true)}
						className="mobile-touch-target"
					>
						Reset local database
					</Button>
					{resetDatabase.error && (
						<Alert variant="destructive">
							<AlertDescription>{String(resetDatabase.error)}</AlertDescription>
						</Alert>
					)}
				</CardContent>
			</Card>
			<Dialog
				open={open}
				onOpenChange={(next) => {
					if (!next) close();
				}}
			>
				<DialogContent className="sm:max-w-md">
					<DialogHeader>
						<DialogTitle>Reset local database</DialogTitle>
						<DialogDescription>
							This deletes the local settings and media index SQLite files. It
							does not affect remote servers.
						</DialogDescription>
					</DialogHeader>
					<div className="flex flex-col gap-3">
						<label className="flex items-center gap-2 text-sm">
							<Checkbox
								className="mobile-touch-target"
								checked={ackSettings}
								onCheckedChange={(checked) => setAckSettings(Boolean(checked))}
							/>
							I understand settings will be lost.
						</label>
						<label className="flex items-center gap-2 text-sm">
							<Checkbox
								className="mobile-touch-target"
								checked={ackIndex}
								onCheckedChange={(checked) => setAckIndex(Boolean(checked))}
							/>
							I understand the media index will be rebuilt.
						</label>
						<label className="flex items-center gap-2 text-sm">
							<Checkbox
								className="mobile-touch-target"
								checked={ackIrreversible}
								onCheckedChange={(checked) =>
									setAckIrreversible(Boolean(checked))
								}
							/>
							I understand this cannot be undone.
						</label>
						<FormField label='Type "reset local database" to confirm'>
							<Input
								value={phrase}
								onChange={(e) => setPhrase(e.target.value)}
							/>
						</FormField>
					</div>
					<DialogFooter
						onCancel={close}
						cancelLabel="Cancel"
						onConfirm={async () => {
							await resetDatabase.mutateAsync({
								confirm_phrase: phrase,
								acknowledge_settings_loss: ackSettings,
								acknowledge_media_index_loss: ackIndex,
								acknowledge_irreversible: ackIrreversible,
							});
							close();
						}}
						confirmLabel="Reset database"
						confirmBusyLabel="Resetting..."
						confirmColor="error"
						confirmDisabled={!canSubmit || resetDatabase.isPending}
					/>
				</DialogContent>
			</Dialog>
		</>
	);
}

export function Settings() {
	const { data: machines, error } = useMonitoringSettings();
	const { data: sshKeys = [] } = useSSHKeys();
	const saveMachine = useSaveMonitoringMachine();
	const deleteMachine = useDeleteMonitoringMachine();
	const testMachineSSH = useTestMonitoringMachineSSH();
	const [searchParams] = useSearchParams();
	const [tab, setTab] = useState<SettingsTab>(
		(searchParams.get("tab") as SettingsTab | null) ?? "machines",
	);
	const initialServiceId = searchParams.get("service") ?? "";
	const [deleteMachineId, setDeleteMachineId] = useState<string | null>(null);
	const [selectedSSHKeyId, setSelectedSSHKeyId] = useState("");
	const [sshValidationMessage, setSSHValidationMessage] = useState("");
	const [sshValidationError, setSSHValidationError] = useState("");
	const [sshValidationStatus, setSSHValidationStatus] = useState("");
	const [machineDialogOpen, setMachineDialogOpen] = useState(false);
	const [machineDraft, setMachineDraft] = useState<MonitoringMachineInput>(
		emptyMachine(),
	);
	const [editingMachine, setEditingMachine] =
		useState<MonitoringMachine | null>(null);
	const [selectedMachineId, setSelectedMachineId] = useState("");
	const isMobile = useIsMobile();
	const orderedMachines = useMemo(() => machines ?? [], [machines]);
	const selectedMachine = useMemo(
		() =>
			orderedMachines.find((machine) => machine.id === selectedMachineId) ??
			orderedMachines[0] ??
			null,
		[orderedMachines, selectedMachineId],
	);
	const clearSSHValidation = () => {
		setSSHValidationMessage("");
		setSSHValidationError("");
		setSSHValidationStatus("");
	};
	const openEditMachine = (
		input: MonitoringMachineInput,
		original?: MonitoringMachine | null,
	) => {
		clearSSHValidation();
		setMachineDraft(input);
		setEditingMachine(original ?? null);
		setMachineDialogOpen(true);
	};
	const closeMachineDialog = () => {
		clearSSHValidation();
		setMachineDialogOpen(false);
		setEditingMachine(null);
	};
	const updateMachineDraft = (
		draft:
			| MonitoringMachineInput
			| ((current: MonitoringMachineInput) => MonitoringMachineInput),
	) => {
		clearSSHValidation();
		setMachineDraft(draft);
	};
	const saveMachineDraft = async (draft: MonitoringMachineInput) => {
		clearSSHValidation();
		await saveMachine.mutateAsync(draft);
		setMachineDialogOpen(false);
		setEditingMachine(null);
		setMachineDraft(emptyMachine(draft.mode));
	};
	const validateMachineSSH = async () => {
		clearSSHValidation();
		try {
			const result = await testMachineSSH.mutateAsync(machineDraft);
			setSSHValidationMessage(result.message);
			setSSHValidationStatus(
				result.known_hosts_updated
					? "Host key trusted and SSH auth succeeded."
					: "Host key already trusted and SSH auth succeeded.",
			);
		} catch (error) {
			const message = error instanceof Error ? error.message : String(error);
			setSSHValidationError(message);
			const lowered = message.toLowerCase();
			if (lowered.includes("protocol banner")) {
				setSSHValidationStatus("SSH banner not received.");
			} else if (
				lowered.includes("no authentication methods available") ||
				lowered.includes("authentication failed")
			) {
				setSSHValidationStatus("SSH authentication failed.");
			} else {
				setSSHValidationStatus("SSH validation failed.");
			}
		}
	};
	return (
		<div className="flex flex-col gap-6">
			<div className="flex flex-col gap-1">
				<h1 className="text-lg font-semibold">Settings</h1>
				<p className="text-xs text-muted-foreground">
					Structure machines, reusable SSH keys, and safety controls from a
					tabbed admin workspace.
				</p>
			</div>
			{error && (
				<Alert variant="destructive">
					<AlertDescription>{String(error)}</AlertDescription>
				</Alert>
			)}
			{saveMachine.error && (
				<Alert variant="destructive">
					<AlertDescription>{String(saveMachine.error)}</AlertDescription>
				</Alert>
			)}
			{deleteMachine.error && (
				<Alert variant="destructive">
					<AlertDescription>{String(deleteMachine.error)}</AlertDescription>
				</Alert>
			)}
			<TabbedCard
				value={tab}
				onChange={(value) => setTab(value as SettingsTab)}
				tabs={[
					<TabsTrigger key="machines" value="machines">
						Machines
					</TabsTrigger>,
					<TabsTrigger key="ssh-keys" value="ssh-keys">
						SSH Keys
					</TabsTrigger>,
					<TabsTrigger key="services" value="services">
						Services
					</TabsTrigger>,
					<TabsTrigger key="dashboards" value="dashboards">
						Dashboards
					</TabsTrigger>,
					<TabsTrigger key="danger" value="danger">
						Danger Zone
					</TabsTrigger>,
				]}
				contentSx={{}}
			>
				{tab === "machines" && (
					<div className="flex flex-col gap-4">
						{orderedMachines.length > 0 ? (
							<div className="grid grid-cols-1 gap-4 md:grid-cols-[320px_minmax(0,1fr)]">
								<SelectionRailCard
									title="Machines"
									description="Select a machine to see its settings."
									minHeight={420}
									footer={
										<Button
											variant="outline"
											size="sm"
											className="mobile-touch-target w-full"
											onClick={() => {
												clearSSHValidation();
												setMachineDraft(emptyMachine("local"));
												setEditingMachine(null);
												setMachineDialogOpen(true);
											}}
										>
											Add machine
										</Button>
									}
								>
									{orderedMachines.map((machine) => {
										const active = machine.id === selectedMachine?.id;
										return (
											<div
												key={machine.id}
												onClick={() => setSelectedMachineId(machine.id)}
												className={cn(
													"group grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] gap-2 border-t border-border px-3 py-2.5 group-hover:[&_.rail-edit]:opacity-100",
													active ? "bg-muted" : "bg-card hover:bg-muted/50",
												)}
											>
												<div className="min-w-0">
													<p className="truncate font-semibold">
														{machine.name}
													</p>
													<p className="text-xs text-muted-foreground">
														{machine.mode} ·{" "}
														{machine.enabled ? "Enabled" : "Disabled"}
													</p>
												</div>
												<HoverEditButton
													onClick={() => {
														openEditMachine(
															{
																id: machine.id,
																name: machine.name,
																mode: machine.mode,
																enabled: machine.enabled,
																services: machine.services,
																host: machine.host,
																port: machine.port,
																username: machine.username,
																key_directory: "",
																key_name: "",
																ssh_key_id: machine.ssh_key_id,
																ssh_private_key: "",
																ssh_private_key_passphrase: "",
																password: "",
																notes: machine.notes,
															},
															machine,
														);
													}}
												/>
											</div>
										);
									})}
								</SelectionRailCard>
								<SectionCard
									title={selectedMachine?.name || "No machine selected"}
									description={
										selectedMachine
											? selectedMachine.mode === "local"
												? "Local API host"
												: `${selectedMachine.username || "user"}@${selectedMachine.host || "host"}:${selectedMachine.port}`
											: "Select a machine on the left to view its settings."
									}
									action={
										selectedMachine ? (
											<Badge variant="outline">{selectedMachine.mode}</Badge>
										) : undefined
									}
								>
									{selectedMachine ? (
										<div className="flex flex-col gap-4">
											<div className="flex flex-row flex-wrap items-center gap-1">
												<Badge variant="outline">
													{selectedMachine.enabled ? "enabled" : "disabled"}
												</Badge>
												<Badge variant="outline">{`${selectedMachine.services.length} services`}</Badge>
												{selectedMachine.ssh_key_id && (
													<Badge variant="outline">{`SSH key ${selectedMachine.ssh_key_id}`}</Badge>
												)}
											</div>
											<p className="text-xs text-muted-foreground">
												{selectedMachine.notes || "No notes."}
											</p>
											<div className="grid grid-cols-1 gap-2 sm:grid-cols-2">
												{selectedMachine.mode === "ssh" ? (
													<>
														<FormField label="Host">
															<Input value={selectedMachine.host} disabled />
														</FormField>
														<FormField label="Port">
															<Input value={selectedMachine.port} disabled />
														</FormField>
														<FormField label="Username">
															<Input
																value={selectedMachine.username}
																disabled
															/>
														</FormField>
													</>
												) : (
													<FormField label="Local hint">
														<Input
															value="Uses the API host directly"
															disabled
														/>
													</FormField>
												)}
											</div>
											<div className="flex flex-row flex-wrap items-center gap-2">
												<Button
													className="mobile-touch-target"
													variant="outline"
													onClick={() =>
														openEditMachine(
															{
																id: selectedMachine.id,
																name: selectedMachine.name,
																mode: selectedMachine.mode,
																enabled: selectedMachine.enabled,
																services: selectedMachine.services,
																host: selectedMachine.host,
																port: selectedMachine.port,
																username: selectedMachine.username,
																key_directory: "",
																key_name: "",
																ssh_key_id: selectedMachine.ssh_key_id,
																ssh_private_key: "",
																ssh_private_key_passphrase: "",
																password: "",
																notes: selectedMachine.notes,
															},
															selectedMachine,
														)
													}
												>
													Edit
												</Button>
												<Button
													className="mobile-touch-target"
													variant="destructive"
													onClick={() => setDeleteMachineId(selectedMachine.id)}
												>
													Delete
												</Button>
											</div>
										</div>
									) : null}
								</SectionCard>
							</div>
						) : null}
					</div>
				)}
				{tab === "ssh-keys" && (
					<SSHKeyManager
						sshKeys={sshKeys}
						selectedKeyId={selectedSSHKeyId}
						onSelectKeyId={setSelectedSSHKeyId}
					/>
				)}
				{tab === "services" && (
					<ServicesAdminCard initialServiceId={initialServiceId} />
				)}
				{tab === "dashboards" && <DashboardManagementCard />}
				{tab === "danger" && <ResetLocalDatabaseCard />}
			</TabbedCard>
			{isMobile ? (
				<SheetForm
					open={machineDialogOpen}
					onOpenChange={(open) => {
						if (!open) closeMachineDialog();
					}}
					title={machineDraft.id ? "Edit machine" : "Create machine"}
					onSave={() => {
						void saveMachineDraft(machineDraft);
					}}
					onCancel={closeMachineDialog}
					isPending={saveMachine.isPending}
					saveDisabled={
						!machineDraft.name ||
						(machineDraft.mode === "ssh" && !machineDraft.host.trim())
					}
					saveLabel={machineDraft.id ? "Save machine" : "Create machine"}
					isDirty={isMachineDraftDirty(machineDraft, editingMachine)}
				>
					<MachineEditor
						key={`${machineDraft.id ?? machineDraft.mode}-${machineDraft.mode}`}
						title={
							machineDraft.id
								? machineDraft.name || "Edit machine"
								: "New machine"
						}
						hint={
							machineDraft.mode === "local" ? "Local API host" : "SSH target"
						}
						machine={machineDraft}
						sshKeys={sshKeys}
						editingMachine={editingMachine}
						onChange={updateMachineDraft}
						onValidateSSH={validateMachineSSH}
						isValidatingSSH={testMachineSSH.isPending}
						sshValidationMessage={sshValidationMessage}
						sshValidationError={sshValidationError}
						sshValidationStatus={sshValidationStatus}
					/>
					{machineDraft.id ? (
						<Button
							className="mobile-touch-target"
							variant="destructive"
							onClick={() => setDeleteMachineId(machineDraft.id as string)}
						>
							Delete machine
						</Button>
					) : null}
				</SheetForm>
			) : (
				<Dialog
					open={machineDialogOpen}
					onOpenChange={(open) => {
						if (!open) closeMachineDialog();
					}}
				>
					<DialogContent className="sm:max-w-4xl">
						<DialogHeader>
							<DialogTitle>
								{machineDraft.id ? "Edit machine" : "Create machine"}
							</DialogTitle>
							<DialogDescription>
								{machineDraft.mode === "local"
									? "Local API host"
									: "SSH target"}
							</DialogDescription>
						</DialogHeader>
						<MachineEditor
							key={`${machineDraft.id ?? machineDraft.mode}-${machineDraft.mode}`}
							title={
								machineDraft.id
									? machineDraft.name || "Edit machine"
									: "New machine"
							}
							hint={
								machineDraft.mode === "local" ? "Local API host" : "SSH target"
							}
							machine={machineDraft}
							sshKeys={sshKeys}
							editingMachine={editingMachine}
							onChange={updateMachineDraft}
							onValidateSSH={validateMachineSSH}
							isValidatingSSH={testMachineSSH.isPending}
							sshValidationMessage={sshValidationMessage}
							sshValidationError={sshValidationError}
							sshValidationStatus={sshValidationStatus}
						/>
						<DialogFooter
							onCancel={closeMachineDialog}
							cancelLabel="Cancel"
							onConfirm={() => {
								void saveMachineDraft(machineDraft);
							}}
							confirmLabel={machineDraft.id ? "Save machine" : "Create machine"}
							confirmDisabled={
								!machineDraft.name ||
								(machineDraft.mode === "ssh" && !machineDraft.host.trim())
							}
							secondaryAction={
								machineDraft.id ? (
									<Button
										className="mobile-touch-target"
										variant="destructive"
										onClick={() => {
											setDeleteMachineId(machineDraft.id as string);
										}}
									>
										Delete
									</Button>
								) : undefined
							}
						/>
					</DialogContent>
				</Dialog>
			)}
			<ConfirmDialog
				open={Boolean(deleteMachineId)}
				title="Delete machine?"
				message="The machine will be removed. Action history will be deleted."
				onCancel={() => setDeleteMachineId(null)}
				onConfirm={() => {
					if (deleteMachineId) {
						deleteMachine.mutate(deleteMachineId);
						closeMachineDialog();
					}
					setDeleteMachineId(null);
				}}
			/>
		</div>
	);
}

/**
 * Services admin card for the Settings > Services tab.
 *
 * Lists all service instances grouped by type with inline config editing
 * (enable/disable, config fields, secrets, save, delete). Lifted from the
 * old ServicePage ConfigBody — the service page is now a pure operational
 * view; all administration lives here.
 */
function ServicesAdminCard({
	initialServiceId = "",
}: {
	initialServiceId?: string;
}) {
	const { data: services = [] } = useServiceInstances();
	const { data: types = [] } = useServiceTypes();
	const [selectedServiceId, setSelectedServiceId] = useState(initialServiceId);
	const [createOpen, setCreateOpen] = useState(false);

	const sortedServices = useMemo(
		() =>
			[...services].sort((a, b) =>
				`${a.service_type}:${a.name}`.localeCompare(
					`${b.service_type}:${b.name}`,
				),
			),
		[services],
	);

	const selectedService = useMemo(
		() =>
			sortedServices.find((s) => s.id === selectedServiceId) ??
			sortedServices[0] ??
			null,
		[sortedServices, selectedServiceId],
	);

	const selectedTypeInfo = selectedService
		? types.find((t) => t.service_type === selectedService.service_type)
		: undefined;

	return (
		<>
			<div className="flex flex-col gap-4">
					<div className="flex justify-end">
							<Button variant="outline" onClick={() => setCreateOpen(true)}>
								Add service
							</Button>
						</div>
						{sortedServices.length === 0 ? (
							<p className="text-sm text-muted-foreground">
								No service instances configured yet.
							</p>
						) : (
							<div className="grid grid-cols-1 gap-4 md:grid-cols-[320px_minmax(0,1fr)]">
								<SelectionRailCard
									title="Services"
									description="Select a service to edit its configuration."
									minHeight={420}
								>
									{sortedServices.map((svc) => {
										const active = svc.id === (selectedService?.id ?? "");
										const typeName =
											types.find((t) => t.service_type === svc.service_type)
												?.name ?? svc.service_type;
										return (
											<div
												key={svc.id}
												onClick={() => setSelectedServiceId(svc.id)}
												className={cn(
													"group grid w-full cursor-pointer grid-cols-[minmax(0,1fr)_auto] gap-2 border-t border-border px-3 py-2.5",
													active ? "bg-muted" : "bg-card hover:bg-muted/50",
												)}
											>
												<div className="min-w-0">
													<p className="truncate font-semibold">{svc.name}</p>
													<p className="text-xs text-muted-foreground">
														{typeName} · {svc.enabled ? "Enabled" : "Disabled"}
													</p>
												</div>
												<Badge variant={svc.enabled ? "default" : "secondary"}>
													{svc.enabled ? "on" : "off"}
												</Badge>
											</div>
										);
									})}
								</SelectionRailCard>
								<SectionCard
									title={selectedService?.name ?? "No service selected"}
									description={
										selectedTypeInfo?.description ??
										"Select a service on the left to edit its configuration."
									}
								>
									{selectedService ? (
										<ServiceConfigEditor
											// Remount on service switch so useState initializers (name, config,
											// secrets) re-run for the new instance. Without this key, switching
											// services in the rail keeps the previous service's editable state
											// and a save writes stale name/config onto the new service's row.
											key={selectedService.id}
											instance={selectedService}
											typeInfo={selectedTypeInfo}
										/>
									) : (
										<p className="text-sm text-muted-foreground">
											Select a service on the left.
										</p>
									)}
								</SectionCard>
							</div>
						)}
					</div>
			<CreateServiceDialog
				open={createOpen}
				onClose={() => setCreateOpen(false)}
			/>
		</>
	);
}

function ServiceConfigEditor({
	instance,
	typeInfo,
}: {
	instance: ServiceInstance;
	typeInfo: ServiceTypeInfo | undefined;
}) {
	const saveService = useSaveServiceInstance();
	const deleteService = useDeleteServiceInstance();
	const testService = useTestServiceInstance();
	const [name, setName] = useState(instance.name);
	const [enabled, setEnabled] = useState(instance.enabled);
	const [draftConfig, setDraftConfig] = useState<Record<string, unknown>>({
		...instance.config,
	});
	const [draftSecrets, setDraftSecrets] = useState<Record<string, string>>({});
	const [deleteOpen, setDeleteOpen] = useState(false);
	const [testResult, setTestResult] = useState<ServiceTestResult | null>(null);
	const [saveAnyway, setSaveAnyway] = useState(false);

	// Build a test input from the current editor state. For the test, include
	// ALL typed secrets (unfiltered) so the backend can authenticate.
	function buildTestInput(): ServiceInstanceInput {
		return {
			id: instance.id,
			service_type: instance.service_type,
			name,
			config: draftConfig,
			secrets: draftSecrets,
			enabled,
		};
	}

	const testInput = buildTestInput();

	// Reset test state when the test input changes (store-previous pattern).
	const [prevTestInput, setPrevTestInput] = useState(testInput);
	if (
		testInput !== prevTestInput &&
		JSON.stringify(testInput) !== JSON.stringify(prevTestInput)
	) {
		setPrevTestInput(testInput);
		setTestResult(null);
		setSaveAnyway(false);
	}

	const testPassed = (testResult?.ok ?? false) || saveAnyway;

	async function handleTest() {
		try {
			const res = await testService.mutateAsync(testInput);
			setTestResult(res);
		} catch (err) {
			setTestResult({
				ok: false,
				detail: err instanceof Error ? err.message : String(err),
				evidence: null,
			});
		}
	}

	const properties =
		(
			(typeInfo?.config_schema ?? {}) as {
				properties?: Record<string, { type?: string; description?: string }>;
			}
		).properties ?? {};
	const configEntries: Array<
		[string, { type?: string; description?: string }]
	> =
		Object.keys(properties).length > 0
			? Object.entries(properties).map(([key, schema]) => [
					key,
					{ type: schema?.type, description: schema?.description },
				])
			: Object.entries(instance.config).map(([key, value]) => [
					key,
					{ type: typeof value === "number" ? "integer" : "string" },
				]);

	function buildInput(): ServiceInstanceInput {
		const onlyChangedSecrets = Object.fromEntries(
			Object.entries(draftSecrets).filter(([, v]) => v !== ""),
		);
		return {
			id: instance.id,
			service_type: instance.service_type,
			name,
			config: draftConfig,
			secrets: onlyChangedSecrets,
			enabled,
		};
	}

	async function handleSave() {
		await saveService.mutateAsync(buildInput());
		setDraftSecrets({});
	}

	return (
		<>
			<div className="rounded-lg border p-4">
				<div className="mb-3 flex items-center justify-between">
					<span className="font-medium">{instance.name}</span>
					<Badge variant={enabled ? "default" : "secondary"}>
						{enabled ? "enabled" : "disabled"}
					</Badge>
				</div>
				<div className="flex flex-col gap-3">
					<FormField label="Name" htmlFor={`svc-name-${instance.id}`}>
						<Input
							id={`svc-name-${instance.id}`}
							value={name}
							onChange={(e) => setName(e.target.value)}
						/>
					</FormField>
					<div className="flex items-center gap-2">
						<Switch
							id={`svc-enabled-${instance.id}`}
							checked={enabled}
							onCheckedChange={setEnabled}
						/>
						<Label htmlFor={`svc-enabled-${instance.id}`}>Enabled</Label>
					</div>

					{configEntries.map(([key, schema]) => {
						const isNumber =
							schema.type === "integer" || schema.type === "number";
						return (
							<FormField
								key={key}
								label={key}
								htmlFor={`svc-cfg-${instance.id}-${key}`}
								helperText={schema.description}
							>
								<Input
									id={`svc-cfg-${instance.id}-${key}`}
									type={isNumber ? "number" : "text"}
									value={String(draftConfig[key] ?? "")}
									onChange={(e) =>
										setDraftConfig({
											...draftConfig,
											[key]: isNumber
												? e.target.value === ""
													? undefined
													: Number(e.target.value)
												: e.target.value,
										})
									}
								/>
							</FormField>
						);
					})}

					{Object.keys(instance.secrets_set).length === 0
						? null
						: Object.entries(instance.secrets_set).map(([key, isSet]) => (
								<FormField
									key={key}
									label={key}
									htmlFor={`svc-secret-${instance.id}-${key}`}
									helperText="Leave blank to keep the current value."
								>
									<Input
										id={`svc-secret-${instance.id}-${key}`}
										type="password"
										placeholder={isSet ? "•••••• (set)" : "Not set"}
										value={draftSecrets[key] ?? ""}
										onChange={(e) =>
											setDraftSecrets({
												...draftSecrets,
												[key]: e.target.value,
											})
										}
									/>
								</FormField>
							))}

					<ServiceTestPanel
						result={testResult}
						isPending={testService.isPending}
						saveAnyway={saveAnyway}
						onTest={handleTest}
						onSaveAnywayChange={setSaveAnyway}
					/>

					<div className="flex justify-between">
						<Button
							onClick={handleSave}
							disabled={saveService.isPending || !testPassed}
							className="mobile-touch-target"
						>
							Save
						</Button>
						<Button
							variant="destructive"
							onClick={() => setDeleteOpen(true)}
							className="mobile-touch-target"
						>
							Delete
						</Button>
					</div>
				</div>
			</div>

			<ConfirmDialog
				open={deleteOpen}
				title="Delete service?"
				message="This removes the service and any widgets that reference it. This cannot be undone."
				confirmLabel="Delete"
				onCancel={() => setDeleteOpen(false)}
				onConfirm={() => {
					deleteService.mutate(instance.id);
					setDeleteOpen(false);
				}}
			/>
		</>
	);
}
