import * as components from './components';
import {enumValues} from './utils';

import {colors} from 'quasar';
// const tinycolor = require('tinycolor2');
import * as changeCase from 'change-case';
import {titleCase} from 'title-case';
import {swapCase} from 'swap-case';
import {isLowerCase} from 'is-lower-case';
import {isUpperCase} from 'is-upper-case';
import lowerCase from 'lower-case';
import {lowerCaseFirst} from 'lower-case-first';
import upperCase from 'upper-case';
import {upperCaseFirst} from 'upper-case-first';
import {spongeCase} from 'sponge-case';

import {lodash} from './packages';


const install = (Vue, {prefix} = {}) => {
  for (let key in components) {
    let _key = prefix ? prefix + key : key;
    Vue.component(_key, components[key]);
  }

  import('./public/icons/svg/icons.css');

  Object.keys(lodash).forEach(k => {
    Vue.prototype[k] = lodash[k];
  });

  Vue.prototype.$changeCase = {
    ...changeCase,
    titleCase,
    swapCase,
    isLowerCase,
    isUpperCase,
    lowerCase,
    lowerCaseFirst,
    upperCase,
    upperCaseFirst,
    spongeCase,
  };

  Vue.prototype.$enumValues = enumValues;

  Vue.mixin({
    data() {
      return {
        $windowWidth: typeof window !== 'undefined' ? window.outerWidth : 0,
        $windowHeight: typeof window !== 'undefined' ? window.outerHeight : 0,
        $scrollY: typeof window !== 'undefined' ? window.scrollY : 0,
      };
    },
    created() {
      this.$q.iconMapFn = (iconName) => {
        if (iconName.startsWith('sp:') === true) {
          const name = iconName.substring(3);

          return {
            cls: 'icon-' + name,
          };
        }
      };
    },
    mounted() {
      window.addEventListener('resize', () => {
        this.$data.$windowWidth = window.outerWidth;
      });
      window.addEventListener('resize', () => {
        this.$data.$windowHeight = window.outerHeight;
      });
      window.addEventListener('scroll', () => {
        this.$data.$scrollY = window.scrollY;
      });
    },
    methods: {
      $getAllCssVars(element = document.body) {
        if (!(element instanceof Element)) {
          throw new TypeError('Expected a DOM element');
        }
        let styles = element.style;
        let cssVars = [];
        for (let i = styles.length; i--;) {
          if (styles[i].startsWith('--')) {
            cssVars.push(styles[i]);
          }
        }
        return cssVars;
      },
      $removeAllCssVars(element = document.body) {
        if (!(element instanceof Element)) {
          throw new TypeError('Expected a DOM element');
        }
        this.$getAllCssVars(element).forEach(k => {
          this.$removeCssVar(k, element);
        });
      },
      $getCssVar(css_var, element = document.body) {
        if (typeof css_var !== 'string') {
          throw new TypeError('Expected a string as css_var');
        }
        if (!(element instanceof Element)) {
          throw new TypeError('Expected a DOM element');
        }
        let styles = getComputedStyle(element);
        let value = String(styles.getPropertyValue(css_var)).trim();
        if (!value) {
          styles = getComputedStyle(document.documentElement);
          value = String(styles.getPropertyValue(css_var)).trim();
        }
        return value || null;
      },
      $setCssVar(css_var, value, element = document.body) {
        if (typeof css_var !== 'string') {
          throw new TypeError('Expected a string as css_var');
        }
        if (typeof value !== 'string') {
          throw new TypeError('Expected a string as value');
        }
        if (!(element instanceof Element)) {
          throw new TypeError('Expected a DOM element');
        }
        let styles = element.style;
        styles.setProperty(css_var, value);
      },
      $removeCssVar(css_var, element = document.body) {
        if (typeof css_var !== 'string') {
          throw new TypeError('Expected a string as css_var');
        }
        if (!(element instanceof Element)) {
          throw new TypeError('Expected a DOM element');
        }
        let styles = element.style;
        styles.removeProperty(css_var);
      },
      $getTextColor(css_var) {
        // let colorVar = tinycolor(this.$getCssVar(css_var));
        // let rgba = colorVar.toRgb();
        let rgba = colors.hexToRgb(this.$getCssVar(css_var));

        if ((rgba['r'] * 0.299) + (rgba['g'] * 0.587) + (rgba['b'] * 0.114) > 186) {
          return 'black';
        } else {
          return 'white';
        }
      },
      $isCssVarDark(css_var) {
        // let colorVar = tinycolor(this.$getCssVar(css_var));
        // let rgba = colorVar.toRgb();
        let rgba = colors.hexToRgb(this.$getCssVar(css_var));

        return (rgba['r'] * 0.299) + (rgba['g'] * 0.587) + (rgba['b'] * 0.114) <= 186;
      },
      $isHexDark(hex) {
        // let colorVar = tinycolor(hex);
        // let rgba = colorVar.toRgb();
        let rgba = colors.hexToRgb(hex);

        return (rgba['r'] * 0.299) + (rgba['g'] * 0.587) + (rgba['b'] * 0.114) <= 186;
      },
      $isLoading(val, options = {}) {
        if (val) {
          this.$q.loading.show({...options});
        } else {
          this.$q.loading.hide();
        }
      },
      $routerPreserve({name, params, query, hash, path} = {}) {
        let routerObj = {};
        if (params && JSON.stringify(params) !== JSON.stringify(this.$route.params)) routerObj.params = params;
        if (query && JSON.stringify(query) !== JSON.stringify(this.$route.query)) routerObj.query = query;
        if (hash && JSON.stringify(hash) !== JSON.stringify(this.$route.hash)) routerObj.hash = hash;
        if (name && name !== this.$route.name) routerObj.name = name;
        if (path && path !== this.$route.path) routerObj.path = path;
        if (Object.keys(routerObj).length) {
          let obj = {
            ...{
              params: this.$route.params,
              query: this.$route.query,
              hash: this.$route.hash,
            },
            ...routerObj,
          };
          this.$router.push(obj).catch((err) => {
            throw new Error(`iy-common-client-lib -> global mixin -> $routerPreserve -> $router.push: ${err}.`);
          });
        }
      },
      $rHistory({name, params, query, hash, path} = {}) {
        let routerObj = {};
        if (params && JSON.stringify(params) !== JSON.stringify(this.$route.params)) routerObj.params = params;
        if (query && JSON.stringify(query) !== JSON.stringify(this.$route.query)) routerObj.query = query;
        if (hash && JSON.stringify(hash) !== JSON.stringify(this.$route.hash)) routerObj.hash = hash;
        if (name && name !== this.$route.name) routerObj.name = name;
        if (path && path !== this.$route.path) routerObj.path = path;
        if (Object.keys(routerObj).length) {
          let obj = {
            ...{
              params: this.$route.params,
              query: this.$route.query,
              hash: this.$route.hash,
            },
            ...routerObj,
          };
          const {href} = this.$router.resolve(obj);
          window.history.pushState({}, null, href);
        }
      },
      $searchExactMatch(item_list, search_query, keys_list) {
        let self = this;
        let lowSearch = search_query.toLowerCase().trim();
        let keys = keys_list;
        if (!lowSearch) return item_list;

        return item_list.filter(function (item) {
          return keys.some(key =>
            String(self.$lget(item, key, '')).toLowerCase().includes(lowSearch),
          );
        });
      },
      $searchOrMatch(item_list, search_query, keys_list) {
        let self = this;
        if (!search_query) return item_list;

        let low_search_list = search_query.toLowerCase().trim().split(/[ ,]+/);
        let searchRegex = new RegExp(low_search_list.join('|'), 'g');
        let keys = keys_list;

        return item_list.filter(function (item) {
          return keys.some(key =>
            String(self.$lget(item, key, '')).toLowerCase().match(searchRegex),
          );
        });
      },
      $searchAndMatch(item_list, search_query, keys_list) {
        let self = this;
        if (!search_query) return item_list;

        let low_search_list = search_query.toLowerCase().trim().split(/[ ,]+/);
        let searchRegex = '(?=.*' + low_search_list.join(')(?=.*') + ')';
        let keys = keys_list;

        return item_list.filter(function (item) {
          return keys.some(key =>
            String(self.$lget(item, key, '')).toLowerCase().match(searchRegex),
          );
        });
      },
      $highlight(words, query, color = 'orange') {
        if (!query) return words;
        let low_search_list = query.toLowerCase().trim().split(/[ ,]+/);
        let iQuery = new RegExp(low_search_list.join('|'), 'ig');

        return words.toString().replace(iQuery, function (matchedTxt) {
          return (`<span style='background-color: ${color};'>` + matchedTxt + '</span>');
        });
      },
    },
  });
};

// auto install
if (typeof window !== 'undefined' && window.Vue) {
  install(window.Vue);
}

export default {install};
