"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = useCurrentColorScheme;
exports.getColorScheme = getColorScheme;
exports.getSystemMode = getSystemMode;

var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var React = _interopRequireWildcard(require("react"));

var _getInitColorSchemeScript = require("./getInitColorSchemeScript");

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

function getSystemMode(mode) {
  if (typeof window !== 'undefined' && mode === 'system') {
    const mql = window.matchMedia('(prefers-color-scheme: dark)');

    if (mql.matches) {
      return 'dark';
    }

    return 'light';
  }

  return undefined;
}

function processState(state, callback) {
  if (state.mode === 'light' || state.mode === 'system' && state.systemMode === 'light') {
    return callback('light');
  }

  if (state.mode === 'dark' || state.mode === 'system' && state.systemMode === 'dark') {
    return callback('dark');
  }

  return undefined;
}

function getColorScheme(state) {
  return processState(state, mode => {
    if (mode === 'light') {
      return state.lightColorScheme;
    }

    if (mode === 'dark') {
      return state.darkColorScheme;
    }

    return undefined;
  });
}

function resolveValue(key, defaultValue) {
  if (typeof window === 'undefined') {
    return undefined;
  }

  let value;

  try {
    value = localStorage.getItem(key) || undefined;
  } catch (e) {// Unsupported
  }

  return value || defaultValue;
}

function useCurrentColorScheme(options) {
  const {
    defaultMode = 'light',
    defaultLightColorScheme,
    defaultDarkColorScheme,
    supportedColorSchemes = [],
    modeStorageKey = _getInitColorSchemeScript.DEFAULT_MODE_STORAGE_KEY,
    colorSchemeStorageKey = _getInitColorSchemeScript.DEFAULT_COLOR_SCHEME_STORAGE_KEY
  } = options;
  const joinedColorSchemes = supportedColorSchemes.join(',');
  const [state, setState] = React.useState(() => {
    const initialMode = resolveValue(modeStorageKey, defaultMode);
    return {
      mode: initialMode,
      systemMode: getSystemMode(initialMode),
      lightColorScheme: resolveValue(`${colorSchemeStorageKey}-light`) || defaultLightColorScheme,
      darkColorScheme: resolveValue(`${colorSchemeStorageKey}-dark`) || defaultDarkColorScheme
    };
  });
  const colorScheme = getColorScheme(state);
  const setMode = React.useCallback(mode => {
    setState(currentState => {
      const newMode = !mode ? defaultMode : mode;

      if (typeof localStorage !== 'undefined') {
        localStorage.setItem(modeStorageKey, newMode);
      }

      return (0, _extends2.default)({}, currentState, {
        mode: newMode,
        systemMode: getSystemMode(newMode)
      });
    });
  }, [modeStorageKey, defaultMode]);
  const setColorScheme = React.useCallback(value => {
    if (!value || typeof value === 'string') {
      if (value && !supportedColorSchemes.includes(value)) {
        console.error(`\`${value}\` does not exist in \`theme.colorSchemes\`.`);
      } else {
        setState(currentState => {
          const newState = (0, _extends2.default)({}, currentState);

          if (!value) {
            // reset to default color scheme
            newState.lightColorScheme = defaultLightColorScheme;
            newState.darkColorScheme = defaultDarkColorScheme;
            return newState;
          }

          processState(currentState, mode => {
            localStorage.setItem(`${colorSchemeStorageKey}-${mode}`, value);

            if (mode === 'light') {
              newState.lightColorScheme = value;
            }

            if (mode === 'dark') {
              newState.darkColorScheme = value;
            }
          });
          return newState;
        });
      }
    } else if (value.light && !supportedColorSchemes.includes(value.light) || value.dark && !supportedColorSchemes.includes(value.dark)) {
      console.error(`\`${value}\` does not exist in \`theme.colorSchemes\`.`);
    } else {
      setState(currentState => {
        const newState = (0, _extends2.default)({}, currentState);

        if (value.light || value.light === null) {
          newState.lightColorScheme = value.light === null ? defaultLightColorScheme : value.light;
        }

        if (value.dark || value.dark === null) {
          newState.darkColorScheme = value.dark === null ? defaultDarkColorScheme : value.dark;
        }

        return newState;
      });

      if (value.light) {
        localStorage.setItem(`${colorSchemeStorageKey}-light`, value.light);
      }

      if (value.dark) {
        localStorage.setItem(`${colorSchemeStorageKey}-dark`, value.dark);
      }
    }
  }, [colorSchemeStorageKey, supportedColorSchemes, defaultLightColorScheme, defaultDarkColorScheme]);
  const handleMediaQuery = React.useCallback(e => {
    if (state.mode === 'system') {
      setState(currentState => (0, _extends2.default)({}, currentState, {
        systemMode: e.matches ? 'dark' : 'light'
      }));
    }
  }, [state.mode]); // Ref hack to avoid adding handleMediaQuery as a dep

  const mediaListener = React.useRef(handleMediaQuery);
  mediaListener.current = handleMediaQuery;
  React.useEffect(() => {
    const handler = (...args) => mediaListener.current(...args); // Always listen to System preference


    const media = window.matchMedia('(prefers-color-scheme: dark)'); // Intentionally use deprecated listener methods to support iOS & old browsers

    media.addListener(handler);
    handler(media);
    return () => media.removeListener(handler);
  }, []); // Save mode, lightColorScheme & darkColorScheme to localStorage

  React.useEffect(() => {
    if (state.mode) {
      localStorage.setItem(modeStorageKey, state.mode);
    }

    processState(state, mode => {
      if (mode === 'light') {
        localStorage.setItem(`${colorSchemeStorageKey}-light`, state.lightColorScheme);
      }

      if (mode === 'dark') {
        localStorage.setItem(`${colorSchemeStorageKey}-dark`, state.darkColorScheme);
      }
    });
  }, [state, colorSchemeStorageKey, modeStorageKey]); // Handle when localStorage has changed

  React.useEffect(() => {
    const handleStorage = event => {
      const value = event.newValue;

      if (typeof event.key === 'string' && event.key.startsWith(colorSchemeStorageKey) && (!value || joinedColorSchemes.match(value))) {
        // If the key is deleted, value will be null then reset color scheme to the default one.
        if (event.key.endsWith('light')) {
          setColorScheme({
            light: value
          });
        }

        if (event.key.endsWith('dark')) {
          setColorScheme({
            dark: value
          });
        }
      }

      if (event.key === modeStorageKey && (!value || ['light', 'dark', 'system'].includes(value))) {
        setMode(value || defaultMode);
      }
    };

    window.addEventListener('storage', handleStorage);
    return () => window.removeEventListener('storage', handleStorage);
  }, [setColorScheme, setMode, modeStorageKey, colorSchemeStorageKey, joinedColorSchemes, defaultMode]);
  return (0, _extends2.default)({}, state, {
    colorScheme,
    setMode,
    setColorScheme
  });
}