import { useState } from "react";
import { useQuery } from "@tanstack/react-query";
import { Link, Outlet, useNavigate } from "@tanstack/react-router";
import * as stylex from "@stylexjs/stylex";
import { useAuth } from "@/auth/store";
import InlineError from "@/lib/InlineError";
import { versionQuery } from "@/lib/queries";
import PauseWidget from "../features/pause/PauseWidget";
import ReadOnlyConfigBanner from "../features/settings/ReadOnlyConfigBanner";
import RestartBanner from "../features/settings/RestartBanner";
import { styles as shared } from "@/ui/styles";
import { colors } from "@/ui/tokens.stylex";

/** The one breakpoint the shell has: below it the sidebar becomes a drawer. */
const WIDE = "@media (min-width: 768px)";
const DARK = "@media (prefers-color-scheme: dark)";

const NAV_ITEMS = [
	{ to: "/", label: "Dashboard" },
	{ to: "/queries", label: "Query Log" },
	{ to: "/live", label: "Live" },
	{ to: "/clients", label: "Clients" },
	{ to: "/groups", label: "Groups" },
	{ to: "/blocklists", label: "Blocklists" },
	{ to: "/rules", label: "Rules" },
	{ to: "/local-dns", label: "Local DNS" },
	{ to: "/upstreams", label: "Upstreams" },
	{ to: "/lookup", label: "Lookup" },
	{ to: "/diagnostics", label: "Diagnostics" },
	{ to: "/settings", label: "Settings" },
] as const;

const styles = stylex.create({
	navList: {
		display: "flex",
		flexDirection: "column",
		gap: "0.25rem",
	},
	navLink: {
		display: "block",
		borderRadius: "0.25rem",
		paddingInline: "0.75rem",
		paddingBlock: "0.375rem",
		textDecorationLine: "none",
	},
	/** The current page reads as a filled chip, heavier than the hover fill. */
	navActive: {
		backgroundColor: { default: "oklch(92% 0.004 286.32)", [DARK]: "oklch(27.4% 0.006 286.033)" },
		color: colors.text,
		fontWeight: 500,
	},
	navIdle: {
		backgroundColor: { default: "transparent", ":hover": colors.surfaceHover },
		color: { default: colors.textSecondary, ":hover": colors.text },
	},
	versionFooter: {
		paddingInline: "1rem",
		paddingBlock: "0.75rem",
		fontSize: "0.75rem",
		lineHeight: "1rem",
		color: colors.textMuted,
	},
	logoutRow: {
		display: "flex",
		alignItems: "center",
		gap: "0.5rem",
	},
	shell: {
		minHeight: "100dvh",
		backgroundColor: colors.surface,
		color: colors.text,
		display: { default: "block", [WIDE]: "grid" },
		gridTemplateColumns: { default: null, [WIDE]: "14rem 1fr" },
	},
	sidebar: {
		display: { default: "none", [WIDE]: "flex" },
		flexDirection: { default: null, [WIDE]: "column" },
		borderRightWidth: 1,
		borderRightStyle: "solid",
		borderRightColor: colors.border,
	},
	brand: {
		paddingInline: "1rem",
		paddingBlock: "1rem",
		fontSize: "1.125rem",
		lineHeight: "1.75rem",
		fontWeight: 600,
	},
	sidebarNav: {
		flex: 1,
		paddingInline: "0.5rem",
	},
	column: {
		display: "flex",
		minHeight: "100dvh",
		flexDirection: "column",
	},
	header: {
		display: "flex",
		alignItems: "center",
		gap: "0.75rem",
		borderBottomWidth: 1,
		borderBottomStyle: "solid",
		borderBottomColor: colors.border,
		paddingInline: "1rem",
		paddingBlock: "0.5rem",
	},
	narrowOnly: {
		display: { default: null, [WIDE]: "none" },
	},
	narrowBrand: {
		fontSize: "1.125rem",
		lineHeight: "1.75rem",
		fontWeight: 600,
		display: { default: null, [WIDE]: "none" },
	},
	headerRight: {
		marginLeft: "auto",
		display: "flex",
		alignItems: "center",
		gap: "0.75rem",
	},
	drawer: {
		borderBottomWidth: 1,
		borderBottomStyle: "solid",
		borderBottomColor: colors.border,
		display: { default: null, [WIDE]: "none" },
	},
	drawerNav: {
		paddingInline: "0.5rem",
		paddingBlock: "0.5rem",
	},
	main: {
		flex: 1,
		padding: "1rem",
	},
});

function NavLinks({ onNavigate }: { onNavigate?: () => void }) {
	return (
		<ul {...stylex.props(styles.navList)}>
			{NAV_ITEMS.map((item) => (
				<li key={item.to}>
					<Link
						to={item.to}
						onClick={onNavigate}
						activeOptions={{ exact: item.to === "/" }}
						activeProps={{
							"aria-current": "page",
							className: stylex.props(styles.navActive).className,
						}}
						inactiveProps={{ className: stylex.props(styles.navIdle).className }}
						{...stylex.props(styles.navLink, shared.focusRing)}
					>
						{item.label}
					</Link>
				</li>
			))}
		</ul>
	);
}

function VersionFooter() {
	const { data } = useQuery(versionQuery());
	return (
		<footer {...stylex.props(styles.versionFooter)}>
			{data === undefined ? "nxdns" : `nxdns v${data.version} (${data.git_commit.slice(0, 7)})`}
		</footer>
	);
}

function LogoutButton() {
	const { authRequired, logout } = useAuth();
	const navigate = useNavigate();
	const [error, setError] = useState<unknown>(null);
	if (authRequired !== true) return null;
	return (
		<div {...stylex.props(styles.logoutRow)}>
			<button
				type="button"
				onClick={() => {
					setError(null);
					void logout().then(
						() => navigate({ to: "/login" }),
						(logoutError: unknown) => setError(logoutError),
					);
				}}
				{...stylex.props(shared.button, shared.focusRing)}
			>
				Log out
			</button>
			{error !== null && <InlineError error={error} />}
		</div>
	);
}

export default function AppShell() {
	const [drawerOpen, setDrawerOpen] = useState(false);
	return (
		<div {...stylex.props(styles.shell)}>
			<aside {...stylex.props(styles.sidebar)}>
				<div {...stylex.props(styles.brand)}>nxdns</div>
				<nav aria-label="Main" {...stylex.props(styles.sidebarNav)}>
					<NavLinks />
				</nav>
				<VersionFooter />
			</aside>
			<div {...stylex.props(styles.column)}>
				<header {...stylex.props(styles.header)}>
					<button
						type="button"
						aria-expanded={drawerOpen}
						aria-controls="mobile-nav"
						onClick={() => setDrawerOpen((open) => !open)}
						{...stylex.props(shared.button, styles.narrowOnly, shared.focusRing)}
					>
						Menu
					</button>
					<span {...stylex.props(styles.narrowBrand)}>nxdns</span>
					<div {...stylex.props(styles.headerRight)}>
						<PauseWidget />
						<LogoutButton />
					</div>
				</header>
				<RestartBanner />
				<ReadOnlyConfigBanner />
				{drawerOpen && (
					<div id="mobile-nav" {...stylex.props(styles.drawer)}>
						<nav aria-label="Main" {...stylex.props(styles.drawerNav)}>
							<NavLinks onNavigate={() => setDrawerOpen(false)} />
						</nav>
						<VersionFooter />
					</div>
				)}
				<main {...stylex.props(styles.main)}>
					<Outlet />
				</main>
			</div>
		</div>
	);
}
