import {
  createContext,
  type FC,
  useCallback,
  useContext,
  useEffect,
  useState,
} from 'react';

import { THEMES } from 'src/constants/env';

type Settings = {
  compact?: boolean;
  direction?: 'ltr' | 'rtl';
  responsiveFontSizes?: boolean;
  roundedCorners?: boolean;
  theme?: string;
  primary?: string;
};

export type SettingsContextValue = {
  settings: Settings;
  saveSettings: (update: Settings) => void;
  setPrimary: (color: string) => void;
  resetPrimary: () => void;
};

type SettingsProviderProps = {};

const initialSettings: Settings = {
  compact: true,
  direction: 'ltr',
  responsiveFontSizes: true,
  roundedCorners: true,
  theme: THEMES.LIGHT,
  primary: '#5664d2',
};

export const restoreSettings = (): Settings | null => {
  let settings = null;

  try {
    const storedData: string | null = window.localStorage.getItem('settings');

    if (storedData) {
      settings = JSON.parse(storedData);
    } else {
      settings = {
        compact: true,
        direction: 'ltr',
        responsiveFontSizes: true,
        roundedCorners: true,
        theme: THEMES.LIGHT,
        primary: '#5664d2',
      };
    }
  } catch (err) {
    console.error(err);
    // If stored data is not a strigified JSON this will fail,
    // that's why we catch the error
  }

  return settings;
};

export const storeSettings = (settings: Settings): void => {
  window.localStorage.setItem('settings', JSON.stringify(settings));
};

const SettingsContext = createContext<SettingsContextValue>({
  settings: initialSettings,
  saveSettings: () => {},
  setPrimary: () => {},
  resetPrimary: () => {},
});

export const SettingsProvider: FC<
  React.PropsWithChildren<SettingsProviderProps>
> = props => {
  const { children } = props;
  const [settings, setSettings] = useState<Settings>(initialSettings);

  useEffect(() => {
    const restoredSettings = restoreSettings();

    if (restoredSettings) {
      setSettings(restoredSettings);
    }
  }, []);

  const saveSettings = useCallback((updatedSettings: Settings): void => {
    setSettings(updatedSettings);
    storeSettings(updatedSettings);
  }, []);

  const setPrimary = useCallback(
    (color: string): void => {
      saveSettings({
        compact: settings.compact,
        direction: settings.direction,
        responsiveFontSizes: settings.responsiveFontSizes,
        roundedCorners: settings.roundedCorners,
        theme: settings.theme,
        primary: color,
      });
    },
    [
      saveSettings,
      settings.compact,
      settings.direction,
      settings.responsiveFontSizes,
      settings.roundedCorners,
      settings.theme,
    ],
  );

  const resetPrimary = useCallback((): void => {
    setPrimary(initialSettings.primary);
  }, [setPrimary]);

  return (
    <SettingsContext.Provider
      value={{
        settings,
        saveSettings,
        setPrimary,
        resetPrimary,
      }}
    >
      {children}
    </SettingsContext.Provider>
  );
};

export const useSettings = () => useContext(SettingsContext);

export const SettingsConsumer = SettingsContext.Consumer;

export default SettingsContext;
