import { lightTheme } from 'folds';
import { atom, useAtomValue } from 'jotai';
import { createContext, useContext, useEffect, useMemo, useState } from 'react';
import { onDarkFontWeight, onLightFontWeight } from '../../config.css';
import { butterTheme, catppuccinMochaTheme, darkTheme, discordTheme, discordDarkerTheme, mochaTheme, silverTheme, stationeryDarkTheme, stationeryTheme, twilightTheme } from '../../colors.css';
import { settingsAtom } from '../state/settings';
import { useSetting } from '../state/hooks/settings';
import { pluginRegistry } from '../features/settings/plugins/PluginAPI';

/** Ephemeral theme id while hovering theme options in settings (not persisted). */
export const themePreviewIdAtom = atom<string | undefined>(undefined);

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

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

export const isStationeryTheme = (theme: Theme | string): boolean => {
  const id = typeof theme === 'string' ? theme : theme.id;
  return id === 'stationery-theme' || id === 'stationery-dark-theme';
};

export const LightTheme: Theme = {
  id: 'light-theme',
  kind: ThemeKind.Light,
  classNames: ['light-theme', 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 DiscordTheme: Theme = {
  id: 'discord-theme',
  kind: ThemeKind.Dark,
  classNames: ['discord-theme', discordTheme, onDarkFontWeight, 'prism-dark'],
};
export const DiscordDarkerTheme: Theme = {
  id: 'discord-darker-theme',
  kind: ThemeKind.Dark,
  classNames: ['discord-darker-theme', discordDarkerTheme, onDarkFontWeight, 'prism-dark'],
};
export const TwilightTheme: Theme = {
  id: 'twilight-theme',
  kind: ThemeKind.Dark,
  classNames: ['twilight-theme', twilightTheme, onDarkFontWeight, 'prism-dark'],
};
export const MochaTheme: Theme = {
  id: 'mocha-theme',
  kind: ThemeKind.Dark,
  classNames: ['mocha-theme', mochaTheme, onDarkFontWeight, 'prism-dark'],
};
export const CatppuccinMochaTheme: Theme = {
  id: 'catppuccin-mocha-theme',
  kind: ThemeKind.Dark,
  classNames: ['catppuccin-mocha-theme', catppuccinMochaTheme, onDarkFontWeight, 'prism-dark'],
};
export const StationeryTheme: Theme = {
  id: 'stationery-theme',
  kind: ThemeKind.Light,
  classNames: ['stationery-theme', 'stationery', stationeryTheme, onLightFontWeight, 'prism-light'],
};
export const StationeryDarkTheme: Theme = {
  id: 'stationery-dark-theme',
  kind: ThemeKind.Dark,
  classNames: ['stationery-dark-theme', 'stationery', stationeryDarkTheme, onDarkFontWeight, 'prism-dark'],
};

export const useThemes = (): Theme[] => {
  const [pluginThemesUpdate, setPluginThemesUpdate] = useState(0);
  
  // Force update when plugins change (this is a simple approach)
  useEffect(() => {
    const interval = setInterval(() => {
      setPluginThemesUpdate(prev => prev + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, []);
  
  const builtInThemes: Theme[] = useMemo(() => [
    LightTheme, SilverTheme, StationeryTheme, StationeryDarkTheme, DarkTheme, ButterTheme, 
    DiscordTheme, DiscordDarkerTheme, TwilightTheme, 
    MochaTheme, CatppuccinMochaTheme
  ], []);
  
  // Convert plugin themes to Theme format
  const pluginThemes: Theme[] = useMemo(() => {
    const themes = pluginRegistry.getPluginThemes();
    return themes.map(pluginTheme => ({
      id: pluginTheme.id,
      kind: pluginTheme.kind === 'dark' ? ThemeKind.Dark : ThemeKind.Light,
      classNames: [
        pluginTheme.className,
        pluginTheme.kind === 'dark' ? onDarkFontWeight : onLightFontWeight,
        pluginTheme.kind === 'dark' ? 'prism-dark' : 'prism-light'
      ]
    }));
  }, [pluginThemesUpdate]);

  return [...builtInThemes, ...pluginThemes];
};

export const useThemeNames = (): Record<string, string> => {
  const [pluginThemesUpdate, setPluginThemesUpdate] = useState(0);
  
  useEffect(() => {
    const interval = setInterval(() => {
      setPluginThemesUpdate(prev => prev + 1);
    }, 1000);
    return () => clearInterval(interval);
  }, []);
  
  return useMemo(() => {
    const builtInNames = {
      [LightTheme.id]: 'Light',
      [SilverTheme.id]: 'Silver',
      [StationeryTheme.id]: 'Stationery',
      [StationeryDarkTheme.id]: 'Stationery Dark',
      [DarkTheme.id]: 'Dark',
      [ButterTheme.id]: 'Butter',
      [DiscordTheme.id]: 'Discord',
      [DiscordDarkerTheme.id]: 'Discord Darker',
      [TwilightTheme.id]: 'Twilight',
      [MochaTheme.id]: 'Mocha',
      [CatppuccinMochaTheme.id]: 'Catppuccin Mocha',
    };
    
    const pluginThemes = pluginRegistry.getPluginThemes();
    const pluginNames = pluginThemes.reduce((acc, theme) => {
      acc[theme.id] = theme.name;
      return acc;
    }, {} as Record<string, string>);
    
    return { ...builtInNames, ...pluginNames };
  }, [pluginThemesUpdate]);
};

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;
};

/** Active theme, or hover-preview theme when browsing the theme menu. */
export const useDisplayTheme = (): Theme => {
  const activeTheme = useActiveTheme();
  const themes = useThemes();
  const previewId = useAtomValue(themePreviewIdAtom);

  if (!previewId) return activeTheme;
  return themes.find((theme) => theme.id === previewId) ?? activeTheme;
};

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;
};
