import { createContext, useCallback, useContext, useEffect, useLayoutEffect, useMemo, useState, ReactNode } from 'react';
import { API_BASE_URL } from '../constants';
import { useAuth } from './AuthContext';
import {
  applyThemeToDocument,
  readStoredThemePreference,
  resolveEffectiveTheme,
  writeStoredThemePreference,
} from '../utils/themePreference';
import type { ThemePreference } from '../utils/themePreference';

export type Theme = ThemePreference;

interface ThemeContextProps {
  theme: Theme;
  effectiveTheme: 'light' | 'dark';
  setTheme: (theme: Theme) => Promise<void>;
}

interface ThemeProviderProps {
  children: ReactNode;
}

const ThemeContext = createContext<ThemeContextProps | undefined>(undefined);

export const ThemeProvider = ({ children }: ThemeProviderProps): JSX.Element => {
  const { isLoggedIn, userInfo, setUserInfo } = useAuth();
  const [theme, setThemeState] = useState<Theme>(readStoredThemePreference);
  const effectiveTheme = useMemo(() => resolveEffectiveTheme(theme), [theme]);

  // Account preferences are authoritative after login, but local optimistic changes update userInfo first.
  useEffect(() => {
    if (!isLoggedIn || !userInfo?.theme) {
      return;
    }

    setThemeState(userInfo.theme);
    writeStoredThemePreference(userInfo.theme);
  }, [isLoggedIn, userInfo?.theme]);

  const setTheme = useCallback(async (newTheme: Theme) => {
    setThemeState(newTheme);
    writeStoredThemePreference(newTheme);

    if (userInfo) {
      setUserInfo({ ...userInfo, theme: newTheme });
    }

    if (!isLoggedIn) {
      return;
    }

    try {
      const response = await fetch(`${API_BASE_URL}/account/theme`, {
        method: 'PUT',
        credentials: 'include',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ theme: newTheme }),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.detail || 'Failed to update theme');
      }
    } catch (error) {
      console.error('Error updating theme on server:', error);
    }
  }, [isLoggedIn, setUserInfo, userInfo]);

  useLayoutEffect(() => {
    applyThemeToDocument(effectiveTheme);
    (window as any).actionPanelAiSetTheme?.(effectiveTheme);
  }, [effectiveTheme]);

  const value: ThemeContextProps = {
    theme,
    effectiveTheme,
    setTheme,
  };

  return <ThemeContext.Provider value={value}>{children}</ThemeContext.Provider>;
};

export const useTheme = (): ThemeContextProps => {
  const context = useContext(ThemeContext);
  if (context === undefined) {
    throw new Error('useTheme must be used within a ThemeProvider');
  }
  return context;
};
