import { lightTheme } from 'folds';
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { onDarkFontWeight, onLightFontWeight } from '../../config.css';
import {
  bloodRedTheme,
  butterTheme,
  classicMatrixTheme,
  cyberpunkTheme,
  darkTheme,
  lotusTerminalLightTheme,
  lotusTerminalTheme,
  midnightTheme,
  oceanTheme,
  silverTheme,
} from '../../colors.css';
import { settingsAtom } from '../state/settings';
import { useSetting } from '../state/hooks/settings';

export enum ThemeKind {
  Light = 'light',
  Dark = 'dark',
}

export type Theme = {
  id: string;
  kind: ThemeKind;
  classNames: string[];
};

export const LightTheme: Theme = {
  id: 'light-theme',
  kind: ThemeKind.Light,
  classNames: [lightTheme, onLightFontWeight, 'prism-light'],
};

export const SilverTheme: Theme = {
  id: 'silver-theme',
  kind: ThemeKind.Light,
  classNames: ['silver-theme', silverTheme, onLightFontWeight, 'prism-light'],
};
export const DarkTheme: Theme = {
  id: 'dark-theme',
  kind: ThemeKind.Dark,
  classNames: ['dark-theme', darkTheme, onDarkFontWeight, 'prism-dark'],
};
export const ButterTheme: Theme = {
  id: 'butter-theme',
  kind: ThemeKind.Dark,
  classNames: ['butter-theme', butterTheme, onDarkFontWeight, 'prism-dark'],
};
export const CyberpunkTheme: Theme = {
  id: 'cyberpunk-theme',
  kind: ThemeKind.Dark,
  classNames: ['cyberpunk-theme', cyberpunkTheme, onDarkFontWeight, 'prism-dark'],
};
export const OceanTheme: Theme = {
  id: 'ocean-theme',
  kind: ThemeKind.Dark,
  classNames: ['ocean-theme', oceanTheme, onDarkFontWeight, 'prism-dark'],
};
export const BloodRedTheme: Theme = {
  id: 'blood-red-theme',
  kind: ThemeKind.Dark,
  classNames: ['blood-red-theme', bloodRedTheme, onDarkFontWeight, 'prism-dark'],
};
export const ClassicMatrixTheme: Theme = {
  id: 'classic-matrix-theme',
  kind: ThemeKind.Dark,
  classNames: ['classic-matrix-theme', classicMatrixTheme, onDarkFontWeight, 'prism-dark'],
};
export const MidnightTheme: Theme = {
  id: 'midnight-theme',
  kind: ThemeKind.Dark,
  classNames: ['midnight-theme', midnightTheme, onDarkFontWeight, 'prism-dark'],
};
export const LotusTerminalTheme: Theme = {
  id: 'lotus-terminal-theme',
  kind: ThemeKind.Dark,
  classNames: ['lotus-terminal-theme', lotusTerminalTheme, onDarkFontWeight, 'prism-tds-dark'],
};
export const LotusTerminalLightTheme: Theme = {
  id: 'lotus-terminal-light-theme',
  kind: ThemeKind.Light,
  classNames: [
    'lotus-terminal-light-theme',
    lotusTerminalLightTheme,
    onLightFontWeight,
    'prism-tds-light',
  ],
};

export const useThemes = (): Theme[] => {
  const themes: Theme[] = useMemo(
    () => [
      LightTheme,
      SilverTheme,
      DarkTheme,
      ButterTheme,
      CyberpunkTheme,
      OceanTheme,
      BloodRedTheme,
      ClassicMatrixTheme,
      MidnightTheme,
    ],
    [],
  );

  return themes;
};

export const useThemeNames = (): Record<string, string> =>
  useMemo(
    () => ({
      [LightTheme.id]: 'Light',
      [SilverTheme.id]: 'Silver',
      [DarkTheme.id]: 'Dark',
      [ButterTheme.id]: 'Butter',
      [CyberpunkTheme.id]: 'Cyberpunk',
      [OceanTheme.id]: 'Ocean',
      [BloodRedTheme.id]: 'Blood Red',
      [ClassicMatrixTheme.id]: 'Classic Matrix',
      [MidnightTheme.id]: 'Midnight',
    }),
    [],
  );

export const useSystemThemeKind = (): ThemeKind => {
  const darkModeQueryList = useMemo(() => window.matchMedia('(prefers-color-scheme: dark)'), []);
  const [themeKind, setThemeKind] = useState<ThemeKind>(
    darkModeQueryList.matches ? ThemeKind.Dark : ThemeKind.Light,
  );

  useEffect(() => {
    const handleMediaQueryChange = () => {
      setThemeKind(darkModeQueryList.matches ? ThemeKind.Dark : ThemeKind.Light);
    };

    darkModeQueryList.addEventListener('change', handleMediaQueryChange);
    return () => {
      darkModeQueryList.removeEventListener('change', handleMediaQueryChange);
    };
  }, [darkModeQueryList, setThemeKind]);

  return themeKind;
};

export const useActiveTheme = (): Theme => {
  const systemThemeKind = useSystemThemeKind();
  const themes = useThemes();
  const [systemTheme] = useSetting(settingsAtom, 'useSystemTheme');
  const [themeId] = useSetting(settingsAtom, 'themeId');
  const [lightThemeId] = useSetting(settingsAtom, 'lightThemeId');
  const [darkThemeId] = useSetting(settingsAtom, 'darkThemeId');

  if (!systemTheme) {
    const selectedTheme = themes.find((theme) => theme.id === themeId) ?? LightTheme;

    return selectedTheme;
  }

  const selectedTheme =
    systemThemeKind === ThemeKind.Dark
      ? (themes.find((theme) => theme.id === darkThemeId) ?? DarkTheme)
      : (themes.find((theme) => theme.id === lightThemeId) ?? LightTheme);

  return selectedTheme;
};

const ThemeContext = createContext<Theme | null>(null);
export const ThemeContextProvider = ThemeContext.Provider;

export const useTheme = (): Theme => {
  const theme = useContext(ThemeContext);
  if (!theme) {
    throw new Error('No theme provided!');
  }

  return theme;
};
