/*
 * Copyright (C) 2023 Xibo Signage Ltd
 *
 * Xibo - Digital Signage - https://xibosignage.com
 *
 * This file is part of Xibo.
 *
 * Xibo is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * any later version.
 *
 * Xibo is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with Xibo.  If not, see <http://www.gnu.org/licenses/>.
 */

const path = require('path');
const webpack = require('webpack');
const {CleanWebpackPlugin} = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const config = {
  // Add common Configurations
  module: {},
};

const mainConfig = Object.assign({}, config, {
  entry: {
    vendor: './ui/bundle_vendor.js',
    style: './ui/bundle_style.js',
    systemTools: './ui/bundle_tools.js',
    templates: './ui/bundle_templates.js',
    xibo: './ui/bundle_xibo.js',
    layoutEditor: './ui/src/layout-editor/main.js',
    playlistEditor: './ui/src/playlist-editor/main.js',
    campaignBuilder: './ui/src/campaign-builder/main.js',
    editorCommon: './ui/bundle_editor_common.js',
    preview: './ui/bundle_preview.js',
    datatables: './ui/bundle_datatables.js',
    codeEditor: './ui/bundle_code_editor.js',
    wysiwygEditor: './ui/bundle_wysiwyg_editor.js',
    leaflet: './ui/bundle_leaflet.js',
    fileUpload: './ui/src/core/file-upload.js',
  },
  output: {
    path: path.resolve(__dirname, 'web/dist'),
    filename: '[name].bundle.min.js',
  },
  target: ['web', 'es5'],
  module: {
    rules: [
      {
        test: /datatables\.net.*/,
        use: [{
          loader: 'imports-loader',
          options: {
            additionalCode: 'var define = false;',
          },
        }],
      },
      {
        test: /\.(css)$/,
        use: [
          'style-loader',
          'css-loader',
        ],
      },
      {
        test: /\.less$/,
        use: [
          'style-loader',
          'css-loader',
          'less-loader',
        ],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [{
          loader: 'style-loader', // inject CSS to page
        }, {
          loader: 'css-loader', // translates CSS into CommonJS modules
        }, {
          loader: 'postcss-loader', // Run post css actions
          options: {
            postcssOptions: {
              plugins: [
                'autoprefixer',
              ],
            },
          },
        }, {
          loader: 'sass-loader', // compiles Sass to CSS
        }],
      },
      {
        test: /\.(woff(2)?|ttf|eot|svg|jpg|gif|png)$/,
        type: 'asset/resource',
        generator: {
          filename: 'assets/[hash][ext][query]',
        },
      },
      {
        test: /\.(csv|tsv)$/,
        use: [
          'csv-loader',
        ],
      },
      {
        test: /\.xml$/,
        use: [
          'xml-loader',
        ],
      },
      {
        test: /\.hbs$/,
        use: [{
          loader: 'handlebars-loader',
          options: {
            helperDirs: path.join(__dirname, 'ui/src/helpers/handlebars'),
            precompileOptions: {
              knownHelpersOnly: false,
            },
          },
        }],
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', {targets: 'defaults'}],
            ],
          },
        },
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin({
      // To make sure it runs only on the first config
      cleanOnceBeforeBuildPatterns: ['**/*', '!pages/**'],
    }),
    new CopyWebpackPlugin({
      patterns: [
        // Copy directory contents to {output}/
        {
          from: 'ui/src/assets',
          to: 'assets',
        },
        {
          from: 'ui/src/vendor',
          to: 'vendor',
        },
      ],
    }),
  ],
});

const pageConfig = Object.assign({}, config, {
  entry: {
    'display-page': './ui/src/pages/display/display-page.js',
    'schedule-page': './ui/src/pages/schedule/schedule-page.js',
    'campaign-page': './ui/src/pages/campaign/campaign-page.js',
    'developer-template-page':
      './ui/src/pages/developer-template/developer-template-page.js',
    'welcome-page': './ui/src/pages/welcome/welcome-page.js',
  },
  output: {
    path: path.resolve(__dirname, 'web/dist/pages'),
    filename: '[name].bundle.min.js',
    libraryTarget: 'window', // Expose the library to the window object
  },
  target: ['web', 'es5'],
  module: {
    rules: [
      {
        test: /datatables\.net.*/,
        use: [{
          loader: 'imports-loader',
          options: {
            additionalCode: 'var define = false;',
          },
        }],
      },
      {
        test: /\.(css)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
        ],
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'less-loader',
        ],
      },
      {
        test: /\.s[ac]ss$/i,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader', // translates CSS into CommonJS modules
          {
            loader: 'postcss-loader', // Run post css actions
            options: {
              postcssOptions: {
                plugins: [
                  'autoprefixer',
                ],
              },
            },
          }, {
            loader: 'sass-loader', // compiles Sass to CSS
          }],
      },
      {
        test: /\.(woff(2)?|ttf|eot|svg|jpg|gif|png)$/,
        type: 'asset/resource',
        generator: {
          filename: 'assets/[hash][ext][query]',
        },
      },
      {
        test: /\.(csv|tsv)$/,
        use: [
          'csv-loader',
        ],
      },
      {
        test: /\.xml$/,
        use: [
          'xml-loader',
        ],
      },
      {
        test: /\.hbs$/,
        use: [{
          loader: 'handlebars-loader',
          options: {
            helperDirs: path.join(__dirname, 'ui/src/helpers/handlebars'),
            precompileOptions: {
              knownHelpersOnly: false,
            },
          },
        }],
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              ['@babel/preset-env', {targets: 'defaults'}],
            ],
          },
        },
      },
    ],
  },
  plugins: [
    new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: '[name].bundle.min.css',
    }),
  ],
});

const moduleConfig = function(env) {
  console.log('webpack env: ', env);
  return Object.assign({}, config, {
    entry: {
      bundle: './modules/src/player_bundle.js',
    },
    output: {
      path: path.resolve(__dirname, 'modules'),
      filename: '[name].min.js',
    },
    optimization: {
      minimize: !(env.local),
    },
    target: ['web', 'es5'],
    module: {
      rules: [
        {
          test: /\.m?js$/,
          exclude: /node_modules/,
          use: {
            loader: 'babel-loader',
            options: {
              sourceType: 'unambiguous',
              presets: [
                [
                  '@babel/preset-env',
                  {
                    corejs: '3.32',
                    useBuiltIns: 'usage',
                    targets: 'defaults',
                  },
                ],
              ],
              plugins: [
                [
                  'polyfill-corejs3',
                  {
                    method: 'usage-global',
                    version: '3.32',
                  },
                ],
                ['@babel/plugin-transform-for-of', {assumeArray: true}],
                '@babel/plugin-transform-nullish-coalescing-operator',
                '@babel/plugin-bugfix-v8-spread-' +
                'parameters-in-optional-chaining',
                '@babel/plugin-transform-optional-chaining',
                '@babel/plugin-transform-arrow-functions',
                '@babel/plugin-transform-object-rest-spread',
                '@babel/plugin-transform-spread',
                '@babel/plugin-transform-parameters',
                '@babel/plugin-transform-destructuring',
                '@babel/plugin-transform-block-scoping',
                '@babel/plugin-transform-template-literals',
              ],
            },
          },
        },
        {
          test: /\.(css)$/,
          use: [
            'style-loader',
            'css-loader',
          ],
        },
      ],
    },
    plugins: [
      new webpack.ProvidePlugin({
        $: 'jquery',
        jQuery: 'jquery',
      }),
      new CleanWebpackPlugin({
        cleanOnceBeforeBuildPatterns: ['modules/*.min.js'],
      }),
      new CopyWebpackPlugin({
        patterns: [
          // Copy directory contents to {output}/
          {
            from: 'node_modules/pdfjs-dist/es5/build/pdf.worker.js',
            to: 'assets/pdfjs/pdf.worker.js',
          },
        ],
      }),
    ],
  });
};

module.exports = (env, argv) => {
  const _moduleConfigFn = moduleConfig(env, argv);
  if (argv.mode === 'development') {
    mainConfig.devtool = 'source-map';
    _moduleConfigFn.devtool = 'source-map';
    pageConfig.devtool = 'source-map';
  }

  if (argv.mode === 'production') {
    mainConfig.devtool = false;
    _moduleConfigFn.devtool = false;
    pageConfig.devtool = false;
  }

  return [mainConfig, pageConfig, _moduleConfigFn];
};
