const { interpolateName } = require('loader-utils');

const generator = require('./replacement-generator');
const helpers = require('./helpers');

class CompiledSprite {
  constructor({ sprite, content, filename }) {
    this.filename = filename;
    this.content = content;
    this.sprite = sprite;
  }
}

module.exports = class SpriteCompiler {
  constructor(config) {
    this.config = config;
    this.symbols = new Map();
  }

  /**
   * @param {mixer.SpriteSymbol} symbol
   */
  addSymbol(symbol) {
    this.symbols.set(symbol.request, symbol);
  }

  /**
   * @return {Replacement[]}
   */
  getReplacements() {
    return Array.from(this.symbols.values())
      .map(s => s.replacements)
      .reduce((acc, r) => acc.concat(r), []);
  }

  /**
   * @return {Array<{filename?: string, symbols: SpriteSymbol[]}>}
   */
  groupBySpriteFileName(compilation) {
    const sprites = [];

    Array.from(this.symbols.keys()).forEach(path => {
      const symbol = this.symbols.get(path);
      const { config, module } = symbol;

      const compilationContext = helpers.getRootCompilation(compilation)
        .compiler.context;

      let filename;
      if (config.filename && config.emit) {
        const issuerPath = module.issuer.resource
          .replace(compilationContext, '')
          .replace(/^\//, '');

        filename = typeof config.filename === 'function'
          ? config.filename(module, issuerPath)
          : config.filename;
      }

      let sprite = sprites.find(s => s.filename === filename);
      if (!sprite) {
        sprite = { symbols: [symbol] };
        if (filename) {
          sprite.filename = filename;
        }
        sprites.push(sprite);
      } else {
        sprite.symbols.push(symbol);
      }
    });

    return sprites;
  }

  /**
   * @param {Compilation} compilation
   * @return {Promise<CompiledSprite[]>}
   */
  compile(compilation) {
    const { spriteClass, spriteConfig } = this.config;

    const promises = this.groupBySpriteFileName(compilation).map(spriteData => {
      const { filename, symbols } = spriteData;

      // eslint-disable-next-line new-cap
      const sprite = new spriteClass(spriteConfig, symbols);

      return sprite.render()
        .then(content => {
          const result = { sprite, content };

          if (filename) {
            result.filename = filename.includes('[hash')
              ? interpolateName(process.cwd(), filename, { content })
              : filename;
          }

          sprite.symbols.forEach(symbol => {
            const { config, request: symbolUrl } = symbol;
            const position = sprite.calculateSymbolPosition(symbol, 'percent');

            symbol.replacements = [
              generator.symbolUrl(symbol, {
                filename: result.filename,
                emit: config.emit,
                spriteType: config.spriteType
              }),

              generator.bgPosLeft(symbolUrl, position),

              generator.bgPosTop(symbolUrl, position),

              generator.bgSizeWidth(symbolUrl, position),

              generator.bgSizeHeight(symbolUrl, position),

              config.publicPath && new generator.Replacement(
                config.publicPath,
                compilation.getPath(config.publicPath)
              )
            ].filter(Boolean);
          });

          return new CompiledSprite(result);
        });
    });

    return Promise.all(promises);
  }
};

@@ -1,16 +1,47 @@
+const Path = require('path');%0A%0A
 const %7B interpol
@@ -1234,26 +1234,252 @@
     
-const issuerPath =
+filename = typeof config.filename === 'function'%0A          ? config.filename(module)%0A          : config.filename;%0A%0A        if (filename.includes('%5Bissuer-name%5D')) %7B%0A          filename = filename.replace(%0A            '%5Bissuer-name%5D',%0A           
  mod
@@ -1500,32 +1500,36 @@
 ource%0A          
+  
+  
 .replace(compila
@@ -1547,32 +1547,36 @@
 , '')%0A          
+    
 .replace(/%5E%5C//, 
@@ -1572,154 +1572,106 @@
 ace(
-/%5E%5C//, '');%0A%0A        filename = typeof config.filename === 'function'%0A          ? config.filename(module, issuerPath)%0A          : config.filename;
+Path.extname(module.issuer.resource), '')%0A              .replace(/%5E%5C//, '')%0A          );%0A        %7D
 %0A   

allow to use filename as a function