import path from 'path';
import postcss from 'postcss';
import slash from 'slash';

const defaultResolutions = [
  '(min--moz-device-pixel-ratio: 1.5)',
  '(-o-min-device-pixel-ratio: 3/2)',
  '(-webkit-min-device-pixel-ratio: 1.5)',
  '(min-device-pixel-ratio: 1.5)',
  '(min-resolution: 144dpi)',
  '(min-resolution: 1.5dppx)'
];

export default postcss.plugin('postcss-at2x', at2x);

function at2x({ identifier = '@2x' } = {}) {
  return function(root) {
    root.eachRule(function(rule) {
      // Create an @media retina rule
      var mediaParent = rule.parent;
      var params = mediaParent.name === 'media' ?
                 combineMediaQuery(mediaParent.params.split(/,\s*/), defaultResolutions) :
                 defaultResolutions.join(', ');
      var media = postcss.atRule({ name: 'media', params: params });

      // Check for any `background-size` declarations. These need to be added
      // again to prevent it being overriden by usage of the `background`
      // shorthand
      var backgroundSize;
      rule.eachDecl('background-size', function(decl) {
        backgroundSize = decl;
      });

      rule.eachDecl(/^background/, function(decl) {
        if (!backgroundWithHiResURL(decl)) {
          return;
        }

        var newRule = postcss.rule({ selector: decl.parent.selector });
        newRule.append(postcss.decl({
          prop: decl.prop,
          value: parseUrl(decl, identifier)
        }));

        if (backgroundSize) {
          newRule.append(postcss.decl(backgroundSize));
        }

        media.append(newRule);
        root.append(media);
      });
    });
  };
}

/**
 * Add all the resolutions to each media query to scope them
 */
function combineMediaQuery(queries, resolutions) {
  return queries.reduce((finalQuery, query) => {
    resolutions.forEach(resolution => finalQuery.push(`${query} and ${resolution}`));
    return finalQuery;
  }, []).join(', ');
}

function parseUrl(decl, identifier) {
  // Strip out `at-2x`
  var val = decl.value.replace(/\s+(at-2x)\s*(;|$)/, '$2');
  decl.value = val;

  var i = val.indexOf('url(');
  var url = val.slice(i + 4, val.indexOf(')', i));
  var ext = path.extname(url);

  // ignore .svg
  if (ext === '.svg') {
    return;
  }

  // @2x url value
  var retinaUrl = path.join(path.dirname(url), path.basename(url, ext) + identifier + ext);

  // path.join uses backslash on windows, which breaks in CSS. Reverse that
  retinaUrl = slash(retinaUrl);

  // Replace all instances of `url(a/path/test.png)` with `url(a/path/test@2x.png)`.
  // This preserves other values set by background such as no-repeat, color etc
  return val.replace(/url\((.*?)\)/g, 'url(' + retinaUrl + ')');
}

function backgroundWithHiResURL(decl) {
  return decl.value.indexOf('url(') !== -1 &&
         decl.value.indexOf('at-2x') !== -1;
}

@@ -473,166 +473,267 @@
 ule(
-function
 (rule)
+ =%3E
  %7B%0A
+%0A
       
-// Create an @media retina rule%0A      var mediaParent = rule.parent;%0A      var params = mediaParent.name === 'media' ?%0A                
+const mediaParent = rule.parent;%0A%0A      // If retina image is within a media query then ensure each size gets%0A      // the retina resolutions%0A      let retinaMediaParams;%0A      if (mediaParent.name === 'media') %7B%0A        retinaMediaParams =
  com
@@ -804,27 +804,52 @@
 ons)
- :
+;
 %0A      
-          
+%7D else %7B%0A        retinaMediaParams =
  def
@@ -886,17 +886,30 @@
     
-var
+%7D%0A%0A      let
  media
+Rule
  = p
@@ -947,17 +947,28 @@
 params: 
-p
+retinaMediaP
 arams %7D)
@@ -1023,17 +1023,52 @@
 arations
-.
+ and keep a reference to it%0A      //
  These n
@@ -1082,25 +1082,16 @@
 be added
-%0A      //
  again t
@@ -1130,16 +1130,25 @@
 usage of
+%0A      //
  the %60ba
@@ -1156,25 +1156,16 @@
 kground%60
-%0A      //
  shortha
@@ -1173,19 +1173,19 @@
 d%0A      
-var
+let
  backgro
@@ -1236,32 +1236,15 @@
 e', 
-function(decl) %7B%0A       
+decl =%3E
  bac
@@ -1261,25 +1261,16 @@
 e = decl
-;%0A      %7D
 );%0A%0A    
@@ -1304,24 +1304,75 @@
 d/, 
-function(decl) %7B
+(decl) =%3E %7B%0A        // Exit if it's a normal background declaration
 %0A   
@@ -1454,15 +1454,121 @@
     
-var new
+// Construct a duplicate rule but with the image urls%0A        // replaced with retina versions%0A        let retina
 Rule
@@ -1620,35 +1620,38 @@
 tor %7D);%0A        
-new
+retina
 Rule.append(post
@@ -1742,24 +1742,72 @@
       %7D));%0A%0A
+        // Add back any %60background-size%60 value%0A
         if (
@@ -1834,19 +1834,22 @@
         
-new
+retina
 Rule.app
@@ -1886,32 +1886,93 @@
 e));%0A        %7D%0A%0A
+        // Add the new rules to the bottom of the stylesheet%0A
         media.ap
@@ -1968,24 +1968,28 @@
    media
+Rule
 .append(
 newRule)
@@ -1980,19 +1980,22 @@
 .append(
-new
+retina
 Rule);%0A 
@@ -2018,16 +2018,20 @@
 nd(media
+Rule
 );%0A     

Refactor main plugin function with ES6 and detailed comments