"use strict";

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

var _lodash = _interopRequireDefault(require("lodash"));

var _postcss = _interopRequireDefault(require("postcss"));

var _browserslist = _interopRequireDefault(require("browserslist"));

var _node = _interopRequireDefault(require("postcss/lib/node"));

var _isFunction = _interopRequireDefault(require("lodash/isFunction"));

var _escapeClassName = _interopRequireDefault(require("../util/escapeClassName"));

var _generateVariantFunction = _interopRequireDefault(require("../util/generateVariantFunction"));

var _parseObjectStyles = _interopRequireDefault(require("../util/parseObjectStyles"));

var _prefixSelector = _interopRequireDefault(require("../util/prefixSelector"));

var _wrapWithVariants = _interopRequireDefault(require("../util/wrapWithVariants"));

var _cloneNodes = _interopRequireDefault(require("../util/cloneNodes"));

var _increaseSpecificity = _interopRequireDefault(require("../util/increaseSpecificity"));

var _postcssSelectorParser = _interopRequireDefault(require("postcss-selector-parser"));

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function parseStyles(styles) {
  if (!Array.isArray(styles)) {
    return parseStyles([styles]);
  }

  return _lodash.default.flatMap(styles, style => style instanceof _node.default ? style : (0, _parseObjectStyles.default)(style));
}

function containsClass(value) {
  return (0, _postcssSelectorParser.default)(selectors => {
    let classFound = false;
    selectors.walkClasses(() => classFound = true);
    return classFound;
  }).transformSync(value);
}

function wrapWithLayer(rules, layer) {
  return _postcss.default.atRule({
    name: 'layer',
    params: layer
  }).append((0, _cloneNodes.default)(Array.isArray(rules) ? rules : [rules]));
}

function _default(plugins, config) {
  const pluginBaseStyles = [];
  const pluginComponents = [];
  const pluginUtilities = [];
  const pluginVariantGenerators = {};

  const applyConfiguredPrefix = selector => {
    return (0, _prefixSelector.default)(config.prefix, selector);
  };

  const getConfigValue = (path, defaultValue) => _lodash.default.get(config, path, defaultValue);

  const browserslistTarget = (0, _browserslist.default)().includes('ie 11') ? 'ie11' : 'relaxed';
  plugins.forEach(plugin => {
    if (plugin.__isOptionsFunction) {
      plugin = plugin();
    }

    const handler = (0, _isFunction.default)(plugin) ? plugin : _lodash.default.get(plugin, 'handler', () => {});
    handler({
      postcss: _postcss.default,
      config: getConfigValue,
      theme: (path, defaultValue) => getConfigValue(`theme.${path}`, defaultValue),
      corePlugins: path => {
        if (Array.isArray(config.corePlugins)) {
          return config.corePlugins.includes(path);
        }

        return getConfigValue(`corePlugins.${path}`, true);
      },
      variants: (path, defaultValue) => {
        if (Array.isArray(config.variants)) {
          return config.variants;
        }

        return getConfigValue(`variants.${path}`, defaultValue);
      },
      target: path => {
        if (_lodash.default.isString(config.target)) {
          return config.target === 'browserslist' ? browserslistTarget : config.target;
        }

        const [defaultTarget, targetOverrides] = getConfigValue('target');

        const target = _lodash.default.get(targetOverrides, path, defaultTarget);

        return target === 'browserslist' ? browserslistTarget : target;
      },
      e: _escapeClassName.default,
      prefix: applyConfiguredPrefix,
      addUtilities: (utilities, options) => {
        const defaultOptions = {
          variants: [],
          respectPrefix: true,
          respectImportant: true
        };
        options = Array.isArray(options) ? Object.assign({}, defaultOptions, {
          variants: options
        }) : _lodash.default.defaults(options, defaultOptions);

        const styles = _postcss.default.root({
          nodes: parseStyles(utilities)
        });

        styles.walkRules(rule => {
          if (options.respectPrefix) {
            rule.selector = applyConfiguredPrefix(rule.selector);
          }

          if (options.respectImportant && _lodash.default.get(config, 'important')) {
            if (config.important === true) {
              rule.walkDecls(decl => decl.important = true);
            } else if (typeof config.important === 'string') {
              if (containsClass(config.important)) {
                throw rule.error(`Classes are not allowed when using the \`important\` option with a string argument. Please use an ID instead.`);
              }

              rule.selectors = rule.selectors.map(selector => {
                return (0, _increaseSpecificity.default)(config.important, selector);
              });
            }
          }
        });
        pluginUtilities.push(wrapWithLayer((0, _wrapWithVariants.default)(styles.nodes, options.variants), 'utilities'));
      },
      addComponents: (components, options) => {
        const defaultOptions = {
          variants: [],
          respectPrefix: true
        };
        options = Array.isArray(options) ? Object.assign({}, defaultOptions, {
          variants: options
        }) : _lodash.default.defaults(options, defaultOptions);

        const styles = _postcss.default.root({
          nodes: parseStyles(components)
        });

        styles.walkRules(rule => {
          if (options.respectPrefix) {
            rule.selector = applyConfiguredPrefix(rule.selector);
          }
        });
        pluginComponents.push(wrapWithLayer((0, _wrapWithVariants.default)(styles.nodes, options.variants), 'components'));
      },
      addBase: baseStyles => {
        pluginBaseStyles.push(...parseStyles(baseStyles));
      },
      addVariant: (name, generator) => {
        pluginVariantGenerators[name] = (0, _generateVariantFunction.default)(generator);
      }
    });
  });
  return {
    base: pluginBaseStyles,
    components: pluginComponents,
    utilities: pluginUtilities,
    variantGenerators: pluginVariantGenerators
  };
}