import { createContext, useContext, useEffect, useMemo, useState } from 'react'; import type { ReactNode } from 'react'; type Theme = 'light' | 'dark'; type ThemeContextValue = { theme: Theme; setTheme: (theme: Theme) => void; toggleTheme: () => void; }; const STORAGE_KEY = 'trading-dashboard-theme-v2'; const ThemeContext = createContext(null); function applyTheme(theme: Theme) { const root = document.documentElement; root.classList.toggle('dark', theme === 'dark'); root.dataset.theme = theme; } function readStoredTheme(): Theme | null { if (typeof window === 'undefined') return null; try { const storage = window.localStorage; if (typeof storage?.getItem !== 'function') return null; const stored = storage.getItem(STORAGE_KEY); return stored === 'light' || stored === 'dark' ? stored : null; } catch { return null; } } function writeStoredTheme(theme: Theme) { try { const storage = window.localStorage; if (typeof storage?.setItem === 'function') { storage.setItem(STORAGE_KEY, theme); } } catch { // Theme persistence is best-effort; restricted storage should not break UI. } } function resolveInitialTheme(): Theme { if (typeof window === 'undefined') return 'light'; const stored = readStoredTheme(); if (stored) return stored; return 'light'; } export function ThemeProvider({ children }: { children: ReactNode }) { const [theme, setThemeState] = useState(() => resolveInitialTheme()); useEffect(() => { applyTheme(theme); writeStoredTheme(theme); }, [theme]); useEffect(() => { const media = window.matchMedia?.('(prefers-color-scheme: dark)'); if (!media) return; const handleChange = () => { if (readStoredTheme()) return; setThemeState(media.matches ? 'dark' : 'light'); }; media.addEventListener?.('change', handleChange); return () => media.removeEventListener?.('change', handleChange); }, []); const value = useMemo(() => ({ theme, setTheme: setThemeState, toggleTheme: () => setThemeState(prev => (prev === 'dark' ? 'light' : 'dark')), }), [theme]); return {children}; } export function useTheme() { const ctx = useContext(ThemeContext); if (!ctx) { throw new Error('useTheme must be used within ThemeProvider'); } return ctx; }