import { getGlobalStates } from '@wener/utils';
import { createStore, useStore } from 'zustand';
import { mutative } from 'zustand-mutative';

export interface UserAgentPreferences {
  colorTheme: 'light' | 'dark';
  contrast: 'no-preference' | 'more' | 'less' | 'custom';
  reducedMotion: 'no-preference' | 'reduce';
  reducedData: 'no-preference' | 'reduce';
  reducedTransparency: 'no-preference' | 'reduce';
  devicePixelRatio: number; // zooming, screen resolution
}

export function getUserAgentPreferenceStore() {
  return getGlobalStates('UserAgentPreferenceStore', () => {
    return createUserAgentPreferenceStore();
  });
}

export function getUserAgentPreferences(): UserAgentPreferences {
  return getUserAgentPreferenceStore().getState();
}

export function useUserAgentPreferences() {
  return useStore(getUserAgentPreferenceStore());
}

function createUserAgentPreferenceStore({ watch = true }: { watch?: boolean } = {}) {
  return createStore(
    mutative<
      UserAgentPreferences & {
        close: () => void;
        reset: () => void;
      }
    >((setState, getState, store) => {
      let initial: UserAgentPreferences = {
        colorTheme: 'light',
        contrast: 'no-preference',
        reducedMotion: 'no-preference',
        reducedData: 'no-preference',
        reducedTransparency: 'no-preference',
        devicePixelRatio: globalThis.devicePixelRatio ?? 1,
      };

      const closer: (() => void)[] = [];
      let reset: () => void = () => undefined;
      if (typeof window === 'undefined' || typeof window.matchMedia === 'undefined') {
      } else {
        let resolution = window.matchMedia(`(resolution: ${window.devicePixelRatio}dppx)`);
        let prefersColorScheme = window.matchMedia('(prefers-color-scheme: dark)');
        let prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)');
        let prefersReducedData = window.matchMedia('(prefers-reduced-data: reduce)');
        let prefersReducedTransparency = window.matchMedia('(prefers-reduced-transparency: reduce)');
        let prefersContrast = window.matchMedia('(prefers-contrast: more)');

        let set = (out: UserAgentPreferences) => {
          out.colorTheme = prefersColorScheme.matches ? 'dark' : 'light';
          out.reducedMotion = prefersReducedMotion.matches ? 'reduce' : 'no-preference';
          out.reducedData = prefersReducedData.matches ? 'reduce' : 'no-preference';
          out.reducedTransparency = prefersReducedTransparency.matches ? 'reduce' : 'no-preference';
          out.contrast = prefersContrast.matches ? 'more' : 'no-preference';
          out.devicePixelRatio = globalThis.devicePixelRatio ?? 1;
        };

        // initial
        set(initial);

        const allQuery = [
          prefersColorScheme,
          prefersReducedMotion,
          prefersReducedData,
          prefersReducedTransparency,
          prefersContrast,
          resolution,
        ];
        const onChange = () => {
          setState((s) => {
            set(s);
            return s;
          });
        };
        reset = onChange;
        if (watch) {
          for (let query of allQuery) {
            query.addEventListener('change', onChange);
            closer.push(() => query.removeEventListener('change', onChange));
          }
        }
      }

      return {
        ...initial,
        close: () => {
          for (let c of closer) {
            c();
          }
          closer.splice(0, closer.length);
        },
        reset,
      };
    }),
  );
}
