import { StyledEngineProvider, ThemeProvider } from "@mui/material";
import { createTheme as muiCreateTheme } from "@mui/material/styles";
import { type ReactNode, useEffect, useState } from "react";

function getColorScheme(): "light" | "dark" {
	let scheme = document.body?.dataset.colorScheme ?? document.documentElement?.dataset.colorScheme ?? "light";

	if (scheme === "auto") {
		return globalThis.matchMedia?.("(prefers-color-scheme: dark)").matches ? "dark" : "light";
	}

	return scheme === "dark" ? "dark" : "light";
}

/**
 * Tracks the color scheme Designsystemet is rendering with. The article template
 * sets `data-color-scheme` on `<body>`, so watch that attribute as well as the
 * OS preference (used when the scheme is `auto`).
 */
function useColorScheme() {
	let [scheme, setScheme] = useState<"light" | "dark">(() => getColorScheme());

	useEffect(() => {
		function update() {
			setScheme(getColorScheme());
		}

		update();

		let observer = new MutationObserver(update);
		observer.observe(document.body, { attributes: true, attributeFilter: ["data-color-scheme"] });
		observer.observe(document.documentElement, { attributes: true, attributeFilter: ["data-color-scheme"] });

		let media = globalThis.matchMedia?.("(prefers-color-scheme: dark)");
		media?.addEventListener("change", update);

		return () => {
			observer.disconnect();
			media?.removeEventListener("change", update);
		};
	}, []);

	return scheme;
}

function buildMuiTheme(mode: "light" | "dark") {
	const s = getComputedStyle(document.body);
	const get = (v: string) => s.getPropertyValue(v).trim();
	const isDark = mode === "dark";

	return muiCreateTheme({
		palette: {
			mode,
			primary: {
				main: get("--ds-color-brand-base-default") || "#116069",
				dark: get("--ds-color-brand-base-hover") || "#0d4b52",
				contrastText: get("--ds-color-brand-base-contrast-default") || "#ffffff",
			},
			secondary: {
				main: get("--ds-color-brand-light-base-default") || "#1a95a2",
			},
			background: {
				default: get("--ds-color-neutral-background-default") || (isDark ? "#17181a" : "#ffffff"),
				paper: get("--ds-color-neutral-background-default") || (isDark ? "#17181a" : "#ffffff"),
			},
			text: {
				primary: get("--ds-color-neutral-text-default") || (isDark ? "#e5e6e7" : "#292c30"),
				secondary: get("--ds-color-neutral-text-subtle") || (isDark ? "#b3b5b7" : "#5b5f64"),
			},
			divider: get("--ds-color-neutral-border-subtle") || (isDark ? "#4e5052" : "#bbbcbd"),
		},
		typography: {
			fontFamily: [
				"-apple-system",
				"BlinkMacSystemFont",
				'"Segoe UI"',
				"Roboto",
				'"Helvetica Neue"',
				"Arial",
				"sans-serif",
				'"Apple Color Emoji"',
				'"Segoe UI Emoji"',
				'"Segoe UI Symbol"',
			].join(","),
		},
		components: {
			MuiTypography: {
				styleOverrides: {
					h1: { fontSize: "2.488rem" },
					h2: { fontSize: "2.074rem" },
					h3: { fontSize: "1.728rem" },
					h4: { fontSize: "1.44rem" },
					h5: { fontSize: "1.2rem" },
					h6: { fontSize: "1rem" },
				},
			},
			MuiAppBar: {
				styleOverrides: {
					root: {
						"& .MuiTypography-h1": {
							fontSize: "1.25rem",
							fontWeight: "500",
						},
					},
				},
			},
			MuiButton: {
				styleOverrides: {
					root: { borderRadius: 2 },
				},
			},
			MuiDialogTitle: {
				styleOverrides: {
					root: {
						fontSize: "1.2rem",
						fontWeight: 500,
						paddingLeft: 16,
						paddingRight: 16,
					},
				},
			},
			MuiFormLabel: {
				styleOverrides: {
					root: { color: get("--ds-color-neutral-text-subtle") || "rgba(0, 0, 0, 0.72)" },
				},
			},
			MuiTextField: { defaultProps: { variant: "filled" } },
			MuiSelect: { defaultProps: { variant: "filled" } },
			MuiFormControl: { defaultProps: { variant: "filled" } },
		},
	});
}

export type MuiThemeProviderProps = {
	children: ReactNode;
};

/**
 * Bridges Designsystemet's colour tokens into a MUI theme, so MUI components
 * (most notably the data grid) follow Designsystemet instead of MUI defaults.
 *
 * This lives in a separate entry point (`@olenbetong/synergi-react/mui`) so apps
 * that have migrated to Designsystemet don't pull ~160 kB of MUI and Emotion
 * into their bundle just by using `AppShell`. Wrap `AppShell` with it in apps
 * that still render MUI components:
 *
 * @example
 * ```tsx
 * import { AppShell } from "@olenbetong/synergi-react";
 * import { MuiThemeProvider } from "@olenbetong/synergi-react/mui";
 *
 * <MuiThemeProvider>
 *   <AppShell>{children}</AppShell>
 * </MuiThemeProvider>
 * ```
 */
export function MuiThemeProvider({ children }: MuiThemeProviderProps) {
	const colorScheme = useColorScheme();

	// Rebuilt whenever the color scheme changes so MUI components (notably the
	// data grid) follow Designsystemet instead of staying stuck in light mode.
	// Also re-read after mount, since the stylesheets are imported from JS and
	// the CSS variables aren't necessarily resolved during the first render.
	const [theme, setTheme] = useState(() => buildMuiTheme(colorScheme));
	useEffect(() => {
		setTheme(buildMuiTheme(colorScheme));
	}, [colorScheme]);

	return (
		<StyledEngineProvider injectFirst>
			<ThemeProvider theme={theme}>{children}</ThemeProvider>
		</StyledEngineProvider>
	);
}
