"use client";
import { jsx as _jsx } from "react/jsx-runtime";
/**
 * ThemeProvider - Client component that provides theme state and management.
 *
 * Features:
 * - Syncs theme to cookie/localStorage
 * - Detects system preference changes
 * - Cross-tab synchronization via storage events
 * - Updates HTML element attribute when theme changes
 * - Handles SSR hydration by deferring system theme detection
 */
import { useCallback, useEffect, useMemo, useState } from "react";
import { ThemeContext } from "./theme-context.js";
import { THEME_COOKIE } from "./constants.js";
/**
 * Get system preference for color scheme
 */
function getSystemTheme() {
    if (typeof window !== "undefined" && window.matchMedia) {
        return window.matchMedia("(prefers-color-scheme: dark)").matches
            ? "dark"
            : "light";
    }
    return "light";
}
/**
 * Read theme from cookie
 */
function readThemeFromCookie(storageKey) {
    if (typeof document === "undefined")
        return null;
    const cookies = document.cookie.split(";");
    for (const cookie of cookies) {
        const [name, ...rest] = cookie.trim().split("=");
        if (name === storageKey) {
            return decodeURIComponent(rest.join("="));
        }
    }
    return null;
}
/**
 * Read theme from localStorage
 */
function readThemeFromStorage(storageKey) {
    if (typeof localStorage === "undefined")
        return null;
    try {
        return localStorage.getItem(storageKey);
    }
    catch {
        return null;
    }
}
/**
 * Write theme to cookie
 */
function writeThemeToCookie(storageKey, theme) {
    if (typeof document === "undefined")
        return;
    const value = encodeURIComponent(theme);
    const cookie = `${storageKey}=${value}; Path=${THEME_COOKIE.path}; Max-Age=${THEME_COOKIE.maxAge}; SameSite=${THEME_COOKIE.sameSite}`;
    document.cookie = cookie;
}
/**
 * Write theme to localStorage
 */
function writeThemeToStorage(storageKey, theme) {
    if (typeof localStorage === "undefined")
        return;
    try {
        localStorage.setItem(storageKey, theme);
    }
    catch {
        // localStorage might be disabled or full
    }
}
/**
 * Apply theme to HTML element
 */
function applyThemeToDocument(theme, config) {
    if (typeof document === "undefined")
        return;
    const resolved = theme === "system" && config.enableSystem
        ? getSystemTheme()
        : theme;
    const value = config.value[resolved] || resolved;
    const el = document.documentElement;
    // Apply attribute
    if (config.attribute === "class") {
        // Remove all theme classes
        for (const t of config.themes) {
            const v = config.value[t] || t;
            el.classList.remove(v);
        }
        // Add current theme class
        el.classList.add(value);
    }
    else {
        el.setAttribute(config.attribute, value);
    }
    // Set color-scheme for native dark mode support
    if (config.enableColorScheme) {
        el.style.colorScheme = resolved;
    }
}
/**
 * Get the resolved stored theme (validated against available themes)
 */
function getStoredTheme(config) {
    const { storageKey, themes, defaultTheme, enableSystem } = config;
    // Try cookie first (for SSR consistency)
    let stored = readThemeFromCookie(storageKey);
    // Fall back to localStorage
    if (!stored) {
        stored = readThemeFromStorage(storageKey);
    }
    // Validate stored value
    if (stored) {
        if (stored === "system" && enableSystem) {
            return "system";
        }
        if (themes.includes(stored)) {
            return stored;
        }
    }
    return defaultTheme;
}
/**
 * ThemeProvider component
 *
 * Provides theme state to the component tree via context.
 * Handles theme persistence, system preference detection, and cross-tab sync.
 */
export function ThemeProvider({ config, initialTheme, children, }) {
    // Track mount state to avoid hydration mismatches
    // During SSR and initial hydration, mounted is false
    const [mounted, setMounted] = useState(false);
    // Initialize theme from prop, storage, or default
    const [theme, setThemeState] = useState(() => {
        if (initialTheme)
            return initialTheme;
        if (typeof window === "undefined")
            return config.defaultTheme;
        return getStoredTheme(config);
    });
    // Track system preference - use stable default during SSR
    const [systemTheme, setSystemTheme] = useState("light");
    // Set mounted after hydration and detect actual system theme
    useEffect(() => {
        setMounted(true);
        setSystemTheme(getSystemTheme());
    }, []);
    // Set theme and persist to storage
    const setTheme = useCallback((newTheme) => {
        setThemeState(newTheme);
        writeThemeToCookie(config.storageKey, newTheme);
        writeThemeToStorage(config.storageKey, newTheme);
        applyThemeToDocument(newTheme, config);
    }, [config]);
    // Listen for system preference changes
    useEffect(() => {
        if (!config.enableSystem)
            return;
        if (typeof window === "undefined" || !window.matchMedia)
            return;
        const mediaQuery = window.matchMedia("(prefers-color-scheme: dark)");
        const handleChange = (e) => {
            const newSystemTheme = e.matches ? "dark" : "light";
            setSystemTheme(newSystemTheme);
            // If current theme is "system", re-apply to update document
            if (theme === "system") {
                applyThemeToDocument("system", config);
            }
        };
        // Modern browsers
        mediaQuery.addEventListener("change", handleChange);
        return () => {
            mediaQuery.removeEventListener("change", handleChange);
        };
    }, [config, theme]);
    // Cross-tab synchronization via localStorage storage event
    useEffect(() => {
        if (typeof window === "undefined")
            return;
        const handleStorageChange = (e) => {
            if (e.key !== config.storageKey)
                return;
            const newTheme = e.newValue;
            if (!newTheme)
                return;
            // Validate and apply
            if (newTheme === "system" ||
                config.themes.includes(newTheme)) {
                setThemeState(newTheme);
                applyThemeToDocument(newTheme, config);
            }
        };
        window.addEventListener("storage", handleStorageChange);
        return () => {
            window.removeEventListener("storage", handleStorageChange);
        };
    }, [config]);
    // Compute resolved theme
    // During SSR (not mounted), use the initial theme or default to avoid hydration mismatch
    const resolvedTheme = useMemo(() => {
        if (!mounted) {
            // During SSR, return the initial theme if it's not "system", otherwise "light"
            // The inline script will apply the correct class before hydration
            if (initialTheme && initialTheme !== "system") {
                return initialTheme;
            }
            return "light";
        }
        if (theme === "system" && config.enableSystem) {
            return systemTheme;
        }
        return theme;
    }, [theme, systemTheme, config.enableSystem, mounted, initialTheme]);
    // Build themes list (include "system" if enabled)
    const themes = useMemo(() => {
        if (config.enableSystem) {
            return ["system", ...config.themes.filter((t) => t !== "system")];
        }
        return config.themes;
    }, [config.themes, config.enableSystem]);
    // Context value
    // During SSR (not mounted), return stable values to avoid hydration mismatch
    const contextValue = useMemo(() => ({
        theme,
        setTheme,
        resolvedTheme,
        // Return stable "light" for systemTheme during SSR - actual value updates after mount
        systemTheme: mounted ? systemTheme : "light",
        themes,
        config,
    }), [theme, setTheme, resolvedTheme, systemTheme, themes, config, mounted]);
    return (_jsx(ThemeContext.Provider, { value: contextValue, children: children }));
}
//# sourceMappingURL=ThemeProvider.js.map