import { type ReactNode, useMemo } from 'react';

import { type PaletteMode } from '@material-hu/mui';
import { ThemeProvider } from '@material-hu/mui/styles';
import { AdapterDateFns } from '@material-hu/mui/x-date-pickers/AdapterDateFns';
import { LocalizationProvider } from '@material-hu/mui/x-date-pickers/LocalizationProvider';
import { createHuGoTheme } from '@material-hu/theme/hugo';

import { DialogLayerProvider } from '@material-hu/components/layers/Dialogs';
import { DrawerLayerProvider } from '@material-hu/components/layers/Drawers';
import { MenuLayerProvider } from '@material-hu/components/layers/Menus';

import { isDarkModeEnabled } from 'src/constants/env';
import { useAuth } from 'src/contexts/JWTContext';
import useThemeMode from 'src/hooks/useThemeMode';
import { getCurrentLocale } from 'src/utils/locale';

// Stable module-level component so callers never trigger a children remount
// when the theme changes — only ThemeProvider re-renders with the new theme.
const HuGoThemeProviderBase = ({
  modeOverride,
  children,
}: {
  modeOverride?: PaletteMode | null;
  children: ReactNode;
}) => {
  const { user } = useAuth();
  const { resolvedMode } = useThemeMode();
  const mode = modeOverride ?? (isDarkModeEnabled ? resolvedMode : undefined);
  const theme = useMemo(
    () => createHuGoTheme(mode ? { mode } : undefined),
    [mode],
  );

  return (
    <LocalizationProvider
      dateAdapter={AdapterDateFns}
      adapterLocale={getCurrentLocale(user)}
    >
      <ThemeProvider theme={theme}>
        <MenuLayerProvider>
          <DialogLayerProvider>
            <DrawerLayerProvider>{children}</DrawerLayerProvider>
          </DialogLayerProvider>
        </MenuLayerProvider>
      </ThemeProvider>
    </LocalizationProvider>
  );
};

const useHuGoTheme = (modeOverride?: PaletteMode | null) => {
  const HuGoThemeProvider = useMemo(() => {
    const Provider = ({ children }: { children: ReactNode }) => (
      <HuGoThemeProviderBase modeOverride={modeOverride}>
        {children}
      </HuGoThemeProviderBase>
    );
    Provider.displayName = 'HuGoThemeProvider';
    return Provider;
  }, [modeOverride]);

  return HuGoThemeProvider;
};

export const withHuGoTheme = <P extends object>(
  Component: React.ComponentType<P>,
) => {
  const Wrapped = (props: P) => {
    const HuGoThemeProvider = useHuGoTheme();
    return (
      <HuGoThemeProvider>
        <Component {...props} />
      </HuGoThemeProvider>
    );
  };
  Wrapped.displayName = `withHuGoTheme(${Component.displayName ?? Component.name ?? 'Component'})`;
  return Wrapped;
};

export default useHuGoTheme;
