/**
 * Module dependencies
 */
var assign = require('object-assign-deep');
var isEmpty = require('lodash.isempty');
var difference = require('lodash.difference');
var bemLinter = require('postcss-bem-linter');
var postcss = require('postcss');
var cssnano = require('cssnano');
var reporter = require('postcss-reporter');
var stylelint = require('stylelint');

/**
 * Module export
 */

module.exports = preprocessor;

/**
 * Default options to PostCSS plugins
 */

var defaults = {
  minify: false,
  lint: false,
  use: [
    'postcss-import',
    'postcss-custom-properties',
    'postcss-calc',
    'postcss-custom-media',
    'autoprefixer',
    'postcss-reporter'
  ],
  'postcss-import': {
    onImport: function(imported) {
      // Update the watch task with the list of imported files
      if (typeof global.watchCSS === 'function') {
        global.watchCSS(imported);
      }
    }
  },
  'postcss-reporter': {
    clearMessages: true
  },
  // http://cssnano.co/optimisations/
  cssnano: {
    calc: false,
    autoprefixer: false,
    mergeRules: false,
    safe: true
  }
};


/**
 * Process CSS
 *
 * @param {String} css
 * @returns {Promise}
 */

function preprocessor(css, options) {
  options = mergeOptions(options);

  var plugins = options.use.map(function(p) {
    var plugin = require(p);
    var settings = options[p];

    return settings ? plugin(settings) : plugin;
  });

  var processor = postcss(plugins);

  if (options.minify) {
    processor.use(cssnano(options.cssnano));
  }

  return processor.process(css, options.postcss);
}

/**
 * Merge options with defaults and set root
 *
 * @param {Object} options
 * @returns {Object} Merged options object
 */

function mergeOptions(options) {
  options = options || {};

  var merged = assign({}, defaults, options);

  // Set some core options
  merged['postcss-import'].root = merged.root;

  // Call beforeLint function and pass processed css to bem-linter
  var beforeLint = merged.beforeLint;
  merged['postcss-import'].transform = function(css, filename) {
    if (typeof beforeLint === 'function') {
      css = beforeLint(css, filename, merged);
    }
    return lintImportedFiles(merged)(css, filename);
  };

  // Allow additional plugins to be merged with the defaults
  // but remove any duplicates so that it respects the new order
  if (!isEmpty(options.use)) {
    var plugins = difference(merged.use, options.use);
    merged.use = plugins.concat(options.use);
  }

  return merged;
}

/**
 * Returns a function to be used by postcss-import
 * Lint each imported component with postcss-bem-linter
 *
 * @param {Object} options
 * @returns {Function} Used by postcss-import transform
 */
function lintImportedFiles(options) {
  return function(css, filename) {
    var processor = postcss();

    if (options.lint) {
      processor.use(stylelint(options.stylelint));
    }

    processor
      .use(bemLinter(options['postcss-bem-linter']))
      .use(reporter(options['postcss-reporter']));

    return processor.process(css, {from: filename}).css;
  };
}

@@ -2174,10 +2174,10 @@
 rged
-)(
+, 
 css,
@@ -2716,30 +2716,10 @@
 ions
-) %7B%0A  return function(
+, 
 css,
@@ -2727,26 +2727,24 @@
 filename) %7B%0A
-  
   var proces
@@ -2761,18 +2761,16 @@
 css();%0A%0A
-  
   if (op
@@ -2779,26 +2779,24 @@
 ons.lint) %7B%0A
-  
     processo
@@ -2836,17 +2836,13 @@
 ));%0A
-  
   %7D%0A%0A
-  
   pr
@@ -2849,20 +2849,16 @@
 ocessor%0A
-    
   .use(b
@@ -2898,20 +2898,16 @@
 ter'%5D))%0A
-    
   .use(r
@@ -2946,18 +2946,16 @@
 r'%5D));%0A%0A
-  
   return
@@ -3001,15 +3001,10 @@
 %7D).css;%0A
-  %7D;%0A
 %7D%0A

Simplify lintImportedFiles by removing extra function