import {
	BrowserRouter,
	Routes,
	Route,
	NavLink,
	useLocation,
	Outlet,
} from "react-router-dom";
import {
	QueryClient,
	QueryClientProvider,
	useQuery,
} from "@tanstack/react-query";
import { useEffect, useMemo, useState } from "react";
import type { LucideIcon } from "lucide-react";
import { AuthProvider, useAuth } from "react-oidc-context";
import { Dashboard } from "./pages/Dashboard";
import { NamedDashboardPage } from "./pages/NamedDashboardPage";
import { Settings } from "./pages/Settings";
import { ServicePage } from "./pages/ServicePage";
import { ServiceTypePage } from "./pages/ServiceTypePage";
import { ServicesPage } from "./pages/ServicesPage";
import { getOidcConfig, isOidcConfigured, setAccessToken } from "./auth";
import { fetchAppVersion } from "./api/client";
import { FRONTEND_VERSION_LABEL } from "./version";
import { usePersistentState } from "./hooks/usePersistentState";
import { useIsMobile } from "./hooks/useIsMobile";
import { useServiceInstances } from "./hooks/useServices";
import { useDashboards } from "./hooks/useDashboards";
import { configuredNavEntries } from "./integrations/navEntries";
import { Button } from "@/components/ui/button";
import {
	Tooltip,
	TooltipContent,
	TooltipProvider,
	TooltipTrigger,
} from "@/components/ui/tooltip";
import {
	Sheet,
	SheetContent,
	SheetHeader,
	SheetTitle,
	SheetTrigger,
} from "@/components/ui/sheet";
import {
	LayoutDashboard,
	Settings as SettingsIcon,
	Menu,
	Sun,
	Moon,
	LogOut,
	ChevronLeft,
	ChevronRight,
	Boxes,
	LayoutTemplate,
} from "lucide-react";

const queryClient = new QueryClient({
	defaultOptions: {
		queries: {
			retry: 1,
			refetchOnWindowFocus: false,
			refetchIntervalInBackground: false,
		},
	},
});

function useDarkMode() {
	const [darkMode, setDarkMode] = usePersistentState<boolean>(
		"dark-mode",
		() => window.matchMedia("(prefers-color-scheme: dark)").matches,
	);

	useEffect(() => {
		const root = document.documentElement;
		if (darkMode) {
			root.classList.add("dark");
		} else {
			root.classList.remove("dark");
		}
	}, [darkMode]);

	return [darkMode, () => setDarkMode((prev) => !prev)] as const;
}

// Navigation items are data-driven (spec R1). Built from configured services + dashboards.
interface NavItem {
	path: string;
	label: string;
	icon: LucideIcon;
}

function useNavItems() {
	const { data: services = [] } = useServiceInstances();
	const { data: dashboards = [] } = useDashboards();

	return useMemo<NavItem[]>(() => {
		const configuredTypes = new Set(
			services.filter((s) => s.enabled).map((s) => s.service_type),
		);
		const serviceEntries = configuredNavEntries(configuredTypes).map((e) => ({
			path: e.path,
			label: e.label,
			icon: e.icon,
		}));
		const dashboardEntries = dashboards.map((d) => ({
			path: `/d/${d.slug}`,
			label: d.label,
			icon: LayoutTemplate,
		}));
		return [
			{ path: "/", label: "Dashboard", icon: LayoutDashboard },
			...dashboardEntries,
			...serviceEntries,
			{ path: "/services", label: "Services", icon: Boxes },
			{ path: "/settings", label: "Settings", icon: SettingsIcon },
		];
	}, [services, dashboards]);
}

function Sidebar({
	collapsed,
	onToggle,
	isMobile,
}: {
	collapsed: boolean;
	onToggle: () => void;
	isMobile: boolean;
}) {
	const location = useLocation();
	const navItems = useNavItems();

	if (isMobile) return null;

	return (
		<aside
			className={`fixed left-0 top-0 z-40 h-screen border-r border-border bg-card transition-all duration-300 ${
				collapsed ? "w-16" : "w-60"
			}`}
		>
			<div className="flex h-full flex-col">
				{/* Logo area */}
				<div className="flex h-14 items-center justify-between border-b border-border px-3">
					<div className="flex items-center gap-2">
						<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-lg bg-primary font-bold text-primary-foreground">
							M
						</div>
						{!collapsed && <span className="font-semibold">Manage</span>}
					</div>
					<Button
						variant="ghost"
						size="icon"
						className="h-8 w-8"
						onClick={onToggle}
					>
						{collapsed ? (
							<ChevronRight className="h-4 w-4" />
						) : (
							<ChevronLeft className="h-4 w-4" />
						)}
					</Button>
				</div>

				{/* Navigation */}
				<nav className="flex-1 space-y-1 p-2">
					<TooltipProvider delayDuration={0}>
						{navItems.map((item) => {
							const isItemActive = location.pathname === item.path;
							const Icon = item.icon;

							return collapsed ? (
								<Tooltip key={item.path}>
									<TooltipTrigger asChild>
										<NavLink
											to={item.path}
											className={() =>
												`flex h-10 w-full items-center justify-center rounded-md transition-colors ${
													isItemActive
														? "bg-primary text-primary-foreground"
														: "text-muted-foreground hover:bg-accent hover:text-foreground"
												}`
											}
										>
											<Icon className="h-5 w-5" />
										</NavLink>
									</TooltipTrigger>
									<TooltipContent side="right">{item.label}</TooltipContent>
								</Tooltip>
							) : (
								<NavLink
									key={item.path}
									to={item.path}
									className={() =>
										`flex h-10 w-full items-center gap-3 rounded-md px-3 transition-colors ${
											isItemActive
												? "bg-primary text-primary-foreground"
												: "text-muted-foreground hover:bg-accent hover:text-foreground"
										}`
									}
								>
									<Icon className="h-5 w-5 shrink-0" />
									<span className="text-sm font-medium">{item.label}</span>
								</NavLink>
							);
						})}
					</TooltipProvider>
				</nav>
			</div>
		</aside>
	);
}

function MobileDrawer() {
	const [open, setOpen] = useState(false);
	const location = useLocation();
	const navItems = useNavItems();

	return (
		<Sheet open={open} onOpenChange={setOpen}>
			<SheetTrigger asChild>
				<Button variant="ghost" size="icon" className="md:hidden">
					<Menu className="h-5 w-5" />
				</Button>
			</SheetTrigger>
			<SheetContent side="left" className="w-60 p-0">
				<SheetHeader className="border-b border-border p-4">
					<SheetTitle className="flex items-center gap-2">
						<div className="flex h-8 w-8 items-center justify-center rounded-lg bg-primary font-bold text-primary-foreground">
							M
						</div>
						<span>Manage</span>
					</SheetTitle>
				</SheetHeader>
				<nav className="space-y-1 p-2">
					{navItems.map((item) => {
						const isItemActive = location.pathname === item.path;
						const Icon = item.icon;
						return (
							<NavLink
								key={item.path}
								to={item.path}
								onClick={() => setOpen(false)}
								className={() =>
									`flex h-10 w-full items-center gap-3 rounded-md px-3 transition-colors ${
										isItemActive
											? "bg-primary text-primary-foreground"
											: "text-muted-foreground hover:bg-accent hover:text-foreground"
									}`
								}
							>
								<Icon className="h-5 w-5 shrink-0" />
								<span className="text-sm font-medium">{item.label}</span>
							</NavLink>
						);
					})}
				</nav>
			</SheetContent>
		</Sheet>
	);
}

function TopBar({
	darkMode,
	authLabel,
	onSignOut,
	onToggleDarkMode,
}: {
	darkMode: boolean;
	authLabel?: string;
	onSignOut?: () => void;
	onToggleDarkMode: () => void;
}) {
	const location = useLocation();
	const { data: appVersion } = useQuery({
		queryKey: ["app-version"],
		queryFn: fetchAppVersion,
		staleTime: 60 * 60 * 1000,
	});
	const backendLabel = appVersion?.backend_label || "…";

	const navItems = useNavItems();
	const pageTitle =
		navItems.find((item) => item.path === location.pathname)?.label ||
		"Dashboard";

	return (
		<header className="sticky top-0 z-30 flex h-14 items-center justify-between border-b border-border bg-background/80 backdrop-blur-md px-4">
			<div className="flex items-center gap-3">
				<MobileDrawer />
				<h1 className="text-lg font-semibold">{pageTitle}</h1>
			</div>

			<div className="flex items-center gap-2">
				<span className="hidden sm:inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium">
					FE {FRONTEND_VERSION_LABEL}
				</span>
				<span className="hidden sm:inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium">
					BE {backendLabel}
				</span>
				{authLabel && (
					<span className="hidden md:inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-medium max-w-[180px] truncate">
						{authLabel}
					</span>
				)}
				<Button
					variant="ghost"
					size="icon"
					onClick={onToggleDarkMode}
					className="h-8 w-8"
				>
					{darkMode ? (
						<Sun className="h-4 w-4" />
					) : (
						<Moon className="h-4 w-4" />
					)}
				</Button>
				{onSignOut && (
					<Button
						variant="ghost"
						size="sm"
						onClick={onSignOut}
						className="gap-2"
					>
						<LogOut className="h-4 w-4" />
						<span className="hidden sm:inline">Logout</span>
					</Button>
				)}
			</div>
		</header>
	);
}

function ShellLayout({
	darkMode,
	authLabel,
	onSignOut,
	onToggleDarkMode,
}: {
	darkMode: boolean;
	authLabel?: string;
	onSignOut?: () => void;
	onToggleDarkMode: () => void;
}) {
	const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
	const isMobile = useIsMobile();

	return (
		<div className="min-h-screen bg-background">
			<Sidebar
				collapsed={sidebarCollapsed}
				onToggle={() => setSidebarCollapsed(!sidebarCollapsed)}
				isMobile={isMobile}
			/>
			<div
				className={`transition-all duration-300 ${
					isMobile ? "" : sidebarCollapsed ? "ml-16" : "ml-60"
				}`}
			>
				<TopBar
					darkMode={darkMode}
					authLabel={authLabel}
					onSignOut={onSignOut}
					onToggleDarkMode={onToggleDarkMode}
				/>
				<main className="p-4 md:p-6">
					<Outlet />
				</main>
			</div>
		</div>
	);
}

function LoadingScreen({ label }: { label: string }) {
	return (
		<div className="min-h-screen grid place-items-center p-4">
			<div className="w-full max-w-md rounded-xl border bg-card p-6 shadow-sm">
				<div className="flex flex-col items-center gap-3 text-center">
					<div className="h-8 w-8 animate-spin rounded-full border-4 border-primary border-t-transparent" />
					<h2 className="text-lg font-semibold">{label}</h2>
				</div>
			</div>
		</div>
	);
}

function SignInScreen({ onSignIn }: { onSignIn: () => void }) {
	return (
		<div className="min-h-screen grid place-items-center p-4">
			<div className="w-full max-w-md rounded-xl border bg-card p-6 shadow-sm">
				<div className="flex flex-col items-center gap-3 text-center">
					<h2 className="text-xl font-semibold">Sign in required</h2>
					<p className="text-sm text-muted-foreground">
						Use your Authentik account to access Manage.
					</p>
					<Button onClick={onSignIn}>Sign in with OIDC</Button>
				</div>
			</div>
		</div>
	);
}

function AuthenticatedApp() {
	const auth = useAuth();
	const [darkMode, toggleDarkMode] = useDarkMode();

	useEffect(() => {
		setAccessToken(auth.user?.access_token ?? null);
	}, [auth.user?.access_token]);

	const authLabel = useMemo(() => {
		const profile = auth.user?.profile as Record<string, unknown> | undefined;
		return String(
			profile?.name ??
				profile?.preferred_username ??
				profile?.email ??
				auth.user?.profile?.sub ??
				"Authenticated",
		);
	}, [auth.user]);

	if (auth.isLoading || auth.activeNavigator) {
		return <LoadingScreen label="Checking sign-in…" />;
	}

	if (auth.error) {
		return (
			<LoadingScreen
				label={`Authentication error: ${auth.error.message || "Unable to sign in"}`}
			/>
		);
	}

	if (!auth.isAuthenticated) {
		return <SignInScreen onSignIn={() => void auth.signinRedirect()} />;
	}

	return (
		<ShellLayout
			darkMode={darkMode}
			authLabel={authLabel}
			onSignOut={() => void auth.signoutRedirect()}
			onToggleDarkMode={toggleDarkMode}
		/>
	);
}

function NotFoundPage() {
	return (
		<div className="flex min-h-[50vh] flex-col items-center justify-center gap-4">
			<h2 className="text-xl font-semibold">Not found</h2>
			<p className="text-sm text-muted-foreground">This page doesn't exist.</p>
			<Button asChild>
				<NavLink to="/">Back to dashboard</NavLink>
			</Button>
		</div>
	);
}

function AppInner() {
	const [darkMode, toggleDarkMode] = useDarkMode();

	return (
		<QueryClientProvider client={queryClient}>
			{isOidcConfigured() ? (
				<AuthProvider {...getOidcConfig()}>
					<BrowserRouter>
						<Routes>
							<Route element={<AuthenticatedApp />}>
								<Route path="/" element={<Dashboard />} />
								<Route path="/d/:slug" element={<NamedDashboardPage />} />
								<Route path="/settings" element={<Settings />} />
								<Route path="/services" element={<ServicesPage />} />
								<Route
									path="/services/:serviceType"
									element={<ServiceTypePage />}
								/>
								<Route
									path="/services/:serviceType/:serviceId"
									element={<ServicePage />}
								/>
								<Route path="*" element={<NotFoundPage />} />
							</Route>
						</Routes>
					</BrowserRouter>
				</AuthProvider>
			) : (
				<BrowserRouter>
					<Routes>
						<Route
							element={
								<ShellLayout
									darkMode={darkMode}
									onToggleDarkMode={toggleDarkMode}
								/>
							}
						>
							<Route path="/" element={<Dashboard />} />
							<Route path="/d/:slug" element={<NamedDashboardPage />} />
							<Route path="/settings" element={<Settings />} />
							<Route path="/services" element={<ServicesPage />} />
							<Route
								path="/services/:serviceType"
								element={<ServiceTypePage />}
							/>
							<Route
								path="/services/:serviceType/:serviceId"
								element={<ServicePage />}
							/>
							<Route path="*" element={<NotFoundPage />} />
						</Route>
					</Routes>
				</BrowserRouter>
			)}
		</QueryClientProvider>
	);
}

export default function App() {
	return <AppInner />;
}
