import * as path from 'path';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import NotifierPlugin from 'webpack-notifier';
import ManifestPlugin from 'webpack-assets-manifest';
import StylelintPlugin from 'stylelint-webpack-plugin';
import EsLintPlugin from 'eslint-webpack-plugin';
import WebpackbarPlugin from 'webpackbar';
import CleanTerminalPlugin from 'clean-terminal-webpack-plugin';
import {CleanWebpackPlugin} from 'clean-webpack-plugin';
import Autoprefixer from 'autoprefixer';

export class Paths {
  #jsSourcePath;
  #scssSourcePath;

  constructor({dir, source, target, js, scss}) {
    this.sourcePath = path.resolve(dir, source);
    this.targetPath = path.resolve(dir, target);
    this.jsSourcePath = js;
    this.scssSourcePath = scss;
  }

  jsEntry(path) {
    return `${this.jsSourcePath}/${path}`;
  }

  scssEntry(path) {
    return `${this.scssSourcePath}/${path}`;
  }
};

const babelConfig = {
  presets: [
    "@babel/preset-env"
  ],
  plugins: [
    ["polyfill-corejs3", { method: "usage-global"}]
  ],
};

const postCssConfig = {
  plugins: [
    Autoprefixer
  ]
};

const styleLintConfig = {
  'extends': 'stylelint-config-standard',
  'plugins': ['stylelint-scss'],
  'customSyntax': 'postcss-scss',
  'rules': {
    'no-empty-source': null,
    //'selector-id-pattern': null,
    'selector-class-pattern': null, // TODO: remove and fix
    'at-rule-no-unknown': null,
    'function-no-unknown': null,
    'declaration-property-value-no-unknown': null,
    'no-invalid-position-at-import-rule': [
      true,
      {
        ignoreAtRules: ["/^use$/"]
      }
    ],
    'scss/at-rule-no-unknown': true,
    'import-notation': null,
    'annotation-no-unknown': null,
  },
};


export const makeConfig = (env, argv, options) => {
  const isProd = argv.mode === 'production',
        isDev = argv.mode === 'development',
        isWatch = typeof argv.watch !== 'undefined' && argv.watch === true,
        {paths,
         entry,
         plugins = [],
         manifestCustomize = (e) => e,
         sassOptions = {}
        } = options;

  return {
    entry,
    output: {
      filename: 'js/[name].[contenthash:8].js',
      path: paths.targetPath,
    },
    context: paths.sourcePath,
    devtool: isDev ? 'source-map' : false,
    watchOptions: {
      ignored: ['node_modules/**']
    },
    performance: {
      hints: false
    },
    plugins: [
      new ManifestPlugin({
        customize(entry) {

          if (
            entry.key.endsWith('.map')
          ) return false;

          const srcdir = path.dirname(entry.key),
                destdir = path.dirname(entry.value);

          if (srcdir !== destdir) {
            entry.key = destdir + '/' + path.basename(entry.key);
          }

          return manifestCustomize(entry);
        }
      }),
      new CleanWebpackPlugin({
        cleanStaleWebpackAssets: !isWatch
      }),
      new MiniCssExtractPlugin({
        filename: 'css/[name].[contenthash:8].css',
        chunkFilename: '[id].[contenthash:8].css'
      }),
      new StylelintPlugin({
        failOnError: !isWatch,
        config: styleLintConfig,
      }),
      new EsLintPlugin({
        overrideConfig: {
          rules: {
            "no-console": isProd ? 2 : 1,
            "no-debugger": isProd ? 2 : 1,
            "no-empty": isProd ? 2 : 1,
            "no-unused-vars": isProd ? 2 : 1,
            "no-constant-condition": isProd ? 2 : 1,
          }
        }
      }),
      new NotifierPlugin(),
      new WebpackbarPlugin(),
      new CleanTerminalPlugin(),
      ...plugins,
    ],

    externals: {
    },

    module: {
      rules: [
        {
          test: /\.js$/i,
          include: paths.sourcePath,
          use: {
            loader: 'babel-loader',
            options: babelConfig,
          }
        },
        {
          test: /\.s[ac]ss$/i,
          include: paths.sourcePath,
          use: [
            MiniCssExtractPlugin.loader,
            'css-loader',
            {
              loader: 'postcss-loader',
              options: {
                postcssOptions: postCssConfig
              }
            },
            {
              loader: 'sass-loader',
              options: sassOptions,
            },
          ],
        },
      ],
    },

  };
};