// Utilities
import { colorToInt, colorToRGB, createRange, darken, getLuma, intToHex, lighten } from "../util/index.mjs";
import { computed, inject, provide, ref, watch } from 'vue'; // Types

export const VuetifyThemeSymbol = Symbol.for('vuetify:theme');
const defaultThemeOptions = {
  defaultTheme: 'light',
  variations: {
    colors: [],
    lighten: 0,
    darken: 0
  },
  themes: {
    light: {
      dark: false,
      colors: {
        background: '#FFFFFF',
        surface: '#FFFFFF',
        primary: '#6200EE',
        'primary-darken-1': '#3700B3',
        secondary: '#03DAC6',
        'secondary-darken-1': '#018786',
        error: '#B00020',
        info: '#2196F3',
        success: '#4CAF50',
        warning: '#FB8C00'
      },
      variables: {
        'border-color': '0, 0, 0',
        'border-opacity': 0.12,
        'disabled-opacity': 0.38,
        'icon-opacity': 0.54
      }
    },
    dark: {
      dark: true,
      colors: {
        background: '#121212',
        surface: '#121212',
        primary: '#BB86FC',
        'primary-darken-1': '#3700B3',
        secondary: '#03DAC5',
        'secondary-darken-1': '#03DAC5',
        error: '#CF6679',
        info: '#2196F3',
        success: '#4CAF50',
        warning: '#FB8C00'
      },
      variables: {
        'border-color': '255, 255, 255',
        'border-opacity': 0.12,
        'disabled-opacity': 0.38,
        'icon-opacity': 0.70
      }
    }
  }
};

const parseThemeOptions = (options = defaultThemeOptions) => {
  if (!options) return { ...defaultThemeOptions,
    isDisabled: true
  };
  return { ...defaultThemeOptions,
    ...options,
    variations: (options == null ? void 0 : options.variations) == null || (options == null ? void 0 : options.variations) === false ? defaultThemeOptions.variations : options.variations
  };
}; // Composables


export function createTheme(options) {
  const parsedOptions = parseThemeOptions(options);
  const styleEl = ref();
  const current = ref(parsedOptions.defaultTheme);
  const themes = ref(parsedOptions.themes);
  const variations = ref(parsedOptions.variations);
  const computedThemes = computed(() => {
    return Object.keys(themes.value).reduce((obj, key) => {
      var _parsedOptions$variat;

      const theme = { ...themes.value[key],
        colors: { ...themes.value[key].colors,
          ...((_parsedOptions$variat = parsedOptions.variations.colors) != null ? _parsedOptions$variat : []).reduce((obj, color) => {
            return { ...obj,
              ...genColorVariations(color, themes.value[key].colors[color])
            };
          }, {})
        }
      };

      for (const color of Object.keys(theme.colors)) {
        if (/on-[a-z]/.test(color) || theme.colors["on-".concat(color)]) continue;
        const onColor = "on-".concat(color);
        theme.colors[onColor] = intToHex(getLuma(theme.colors[color]) > 0.18 ? 0x0 : 0xffffff);
      }

      obj[key] = theme;
      return obj;
    }, {});
  });

  function genColorVariations(name, color) {
    const obj = {};

    for (const variation of ['lighten', 'darken']) {
      const fn = variation === 'lighten' ? lighten : darken;

      for (const amount of createRange(variations.value[variation], 1)) {
        obj["".concat(name, "-").concat(variation, "-").concat(amount)] = intToHex(fn(colorToInt(color), amount));
      }
    }

    return obj;
  }

  function genCssVariables(name) {
    const theme = computedThemes.value[name];
    if (!theme) throw new Error("Could not find theme ".concat(name));
    const lightOverlay = theme.dark ? 2 : 1;
    const darkOverlay = theme.dark ? 1 : 2;
    const variables = [];

    for (const [key, value] of Object.entries(theme.colors)) {
      const rgb = colorToRGB(value);
      variables.push("--v-theme-".concat(key, ": ").concat(rgb.r, ",").concat(rgb.g, ",").concat(rgb.b));

      if (!key.startsWith('on-')) {
        variables.push("--v-theme-".concat(key, "-overlay-multiplier: ").concat(getLuma(value) > 0.18 ? lightOverlay : darkOverlay));
      }
    }

    return variables;
  }

  function genStyleElement() {
    if (typeof document === 'undefined' || styleEl.value) return;
    const el = document.createElement('style');
    el.type = 'text/css';
    el.id = 'vuetify-theme-stylesheet';
    styleEl.value = el;
    document.head.appendChild(styleEl.value);
  }

  function createCssClass(selector, content) {
    return ["".concat(selector, " {\n"), ...content.map(line => "  ".concat(line, ";\n")), '}\n'];
  }

  function updateStyles() {
    if (parsedOptions.isDisabled) return;
    genStyleElement();
    const lines = [];

    for (const themeName of Object.keys(computedThemes.value)) {
      const variables = computedThemes.value[themeName].variables;
      lines.push(...createCssClass(".v-theme--".concat(themeName), [...genCssVariables(themeName), ...Object.keys(variables).map(key => {
        return "--v-".concat(key, ": ").concat(variables[key]);
      })]));
    } // Assumption is that all theme objects have the same keys, so it doesn't matter which one
    // we use since the values are all css variables.


    const firstTheme = Object.keys(computedThemes.value)[0];

    for (const key of Object.keys(computedThemes.value[firstTheme].colors)) {
      if (/on-[a-z]/.test(key)) {
        lines.push(...createCssClass(".".concat(key), ["color: rgb(var(--v-theme-".concat(key, "))")]));
      } else {
        lines.push(...createCssClass(".bg-".concat(key), ["--v-theme-overlay-multiplier: var(--v-theme-".concat(key, "-overlay-multiplier)"), "background: rgb(var(--v-theme-".concat(key, "))"), "color: rgb(var(--v-theme-on-".concat(key, "))")]), ...createCssClass(".text-".concat(key), ["color: rgb(var(--v-theme-".concat(key, "))")]), ...createCssClass(".border-".concat(key), ["--v-border-color: var(--v-theme-".concat(key, ")")]));
      }
    }

    if (styleEl.value) styleEl.value.innerHTML = lines.map((str, i) => i === 0 ? str : "    ".concat(str)).join('');
  }

  watch(themes, updateStyles, {
    deep: true,
    immediate: true
  });
  return {
    isDisabled: parsedOptions.isDisabled,
    themes: computedThemes,
    setTheme: (key, theme) => themes.value[key] = theme,
    getTheme: key => computedThemes.value[key],
    current,
    themeClasses: computed(() => parsedOptions.isDisabled ? '' : "v-theme--".concat(current.value)),
    hasColor: color => !!computedThemes.value[current.value].colors[color]
  };
}
/**
 * Used to either set up and provide a new theme instance, or to pass
 * along the closest available already provided instance.
 *
 * A new theme instance will be created if either `theme` prop is provided,
 * or if `newContext` prop is true
 */

export function provideTheme(props = {}, context) {
  const theme = inject(VuetifyThemeSymbol, null);
  if (!theme) throw new Error('Could not find Vuetify theme injection');
  const internal = ref(null);
  const current = computed({
    get: () => {
      var _ref, _internal$value;

      return (_ref = (_internal$value = internal.value) != null ? _internal$value : props.theme) != null ? _ref : theme == null ? void 0 : theme.current.value;
    },

    set(value) {
      if (theme && !props.theme && !props.newContext) {
        theme.current.value = value;
      } else {
        internal.value = value;
        context.emit('update:theme', value);
      }
    }

  });
  const themeClasses = computed(() => theme.isDisabled ? '' : "v-theme--".concat(current.value));
  const newTheme = { ...theme,
    current,
    themeClasses
  };
  provide(VuetifyThemeSymbol, newTheme);
  return newTheme;
}
/**
 * Injects and returns closest available provided theme instance.
 */

export function useTheme() {
  const theme = inject(VuetifyThemeSymbol);
  if (!theme) throw new Error('Could not find Vuetify theme injection');
  return theme;
}
//# sourceMappingURL=theme.mjs.map