// const fs = require("fs");
const webpack = require("webpack");
const v4 = require("uuid/v4");
const path = require("path");
const MemoryFS = require("memory-fs");
// const child_process = require("child_process");
const loaderUtils = require("loader-utils");
const ExtractTextPlugin = require("extract-text-webpack-plugin")

const externalDeps = {
  react: "root React",
  lodash: "root _",
  'lodash/fp': "root _",
  "prop-types": "root PropTypes",
  classnames: "root classNames",
  'react-dom': "root ReactDOM"
};

const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));

module.exports = (lock => {
  return async function buildBlock(location, opts = {}) {
    // const cwd = process.cwd()
    const resolve = (module) => path.resolve(__dirname, '../../node_modules', module)
    const fs = new MemoryFS();
    const uuid = v4();
    const config = {
      stats: "verbose",
      entry: './src/index.js',
      output: {
        path: `/block/${uuid}`,
        filename: "bundle.js",
        libraryTarget: "commonjs"
      },
      context: location,
      resolveLoader: {
        modules: [path.resolve(__dirname, '../../node_modules')]
      },
      resolve: {
        extensions: [ '.js' ],
        modules: [path.resolve(location, 'node_modules')]
      },
      module: {
        rules: [
          {
            test: /\.(js|jsx)$/,
            loader: "babel-loader",
            exclude: /node_modules\/(?!wireframe-.*)/,
            options: {
              presets: [
                require(resolve("babel-preset-env")),
                require(resolve("babel-preset-react")),
              ],
              plugins: [
                require(resolve("babel-plugin-transform-class-properties")),
                require(resolve("babel-plugin-transform-object-rest-spread")),
              ]
            }
          },
          {
            include: /node_modules/,
            test: /\.s?css$/,
            use: ExtractTextPlugin.extract({
              fallback: `style-loader`,
              use: [{
                loader: `css-loader`,
                options: {
                  modules: false,
                },
              }],
            }),
          },
          {
            test: /\.s?css$/,
            exclude: /node_modules/,
            use: ExtractTextPlugin.extract({
              fallback: "style-loader",
              use: [{
                loader: "css-loader",
                options: {
                  url: false,
                  modules: true,
                  localIdentName: '[local]__[hash:base64:5]',
                  importLoaders: 1,
                  getLocalIdent: (
                    loaderContext,
                    localIdentName,
                    localName,
                    options
                  ) => {
                    if (!options.context)
                      options.context =
                      loaderContext.options &&
                      typeof loaderContext.options.context === "string"
                        ? loaderContext.options.context
                        : loaderContext.context;

                    const time = new Date()
                    options.content = localName + (time.getTime() / 1000 | 0)
                    localIdentName = localIdentName.replace(/\[local\]/gi, localName)
                    const hash = loaderUtils.interpolateName(
                      loaderContext,
                      localIdentName,
                      options
                    );
                    return hash
                  }
                }
              },
              {
                loader: 'postcss-loader', // translates CSS into CommonJS
                options: {
                  ident: 'postcss',
                  plugins: () => [
                    require('postcss-import'),
                    require('postcss-nested'),
                    require('postcss-custom-media'),
                    require('../../app/sandbox/webpack/postcss-css-variables/index.js'),
                    require('postcss-url-mapper')((data) => {
                      if (opts.urlLoader) {
                        return opts.urlLoader(data)
                      }
                      return data
                    }),
                    require('postcss-flexbugs-fixes'),
                  ]
                },
              }]
            })
          }
        ]
      },
      externals: (context, request, callback) => {
        if (request.startsWith('weblium/editor')) {
          return callback(null, `weblium/editor`)
        }
        if (request.match(/css-loader\/lib\/css-base\.js/)) {
          return callback(null, 'root cssLoader')
        }
        if (request.match(/iso-morphic-style-loader/)) {
          return callback(null, 'root styleLoader')
        }

        return externalDeps[request] ? callback(null, externalDeps[request]) : callback();
      },
      plugins: [
        new ExtractTextPlugin('styles.css'),
        new webpack.optimize.UglifyJsPlugin(),
      ],
    };
    const compiler = webpack(config);

    compiler.outputFileSystem = fs;

    while (lock) await sleep(10);
    lock = true;
    try {
      return await new Promise((resolve, reject) =>
        compiler.run((err, stats) => {
          if (err) {
            return reject(err);
          }
          if (stats.hasErrors()) {
            return reject(stats.toJson());
          }
          const content = fs.readFileSync(`/block/${uuid}/bundle.js`, "utf8");
          const styles = fs.readFileSync(`/block/${uuid}/styles.css`, "utf8");
          const styleString = `
/*--styles-start--*/
  function returnStyles() {
    return ${JSON.stringify(styles)}
}
/*--styles-end--*/`
          const result = content + '\n' + styleString
          resolve(result);
        })
      );
    } finally {
      lock = false;
    }
  }
})(false);
