const path = require('path');
const fs = require('fs');
const CompressionPlugin = require('compression-webpack-plugin');
const autoprefixer = require('autoprefixer');
const precss = require('precss');
const _ = require('lodash');
const Copy = require('copy-webpack-plugin');
const LicenseWebpackPlugin = require('license-webpack-plugin');
const webpack = require('webpack');

// Possibly load the config from the .env file (if there is one).
require('dotenv').config();

const {plugins, pluginsPath, PluginManager} = require('./plugins');
const manager = new PluginManager(plugins);
const targetPlugins = manager.section('targets').plugins;

console.log(`Using ${pluginsPath} as the plugin configuration path`);

const buildTargets = [
  'coral-admin',
  'coral-docs'
];

const buildEmbeds = [
  'stream'
];

//==============================================================================
// Base Webpack Config
//==============================================================================

const config = {
  devtool: 'cheap-module-source-map',
  output: {
    path: path.join(__dirname, 'dist'),
    publicPath: '/client/',
    filename: '[name].js'
  },
  module: {
    rules: [
      {
        loader: 'plugins-loader',
        test: /\.(json|js)$/,
        include: pluginsPath
      },
      {
        loader: 'babel-loader',
        exclude: /node_modules/,
        test: /\.js$/,
        query: {
          cacheDirectory: true
        }
      },
      {
        loader: 'json-loader',
        test: /\.(json|yml)$/,
        exclude: /node_modules/
      },
      {
        loader: 'yaml-loader',
        exclude: /node_modules/,
        test: /\.yml$/,
      },
      {
        loaders: [
          'style-loader',
          'css-loader?modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]',
          'postcss-loader'
        ],
        test: /.css$/,
      },
      {
        loader: 'url-loader?limit=100000',
        test: /\.png$/
      },
      {
        loader: 'file-loader',
        test: /\.(jpg|png|gif|svg)$/
      },
      {
        loader: 'url-loader?limit=100000',
        test: /\.woff$/
      },
      {
        test: /\.(graphql|gql)$/,
        exclude: /node_modules/,
        loader: 'graphql-tag/loader'
      }
    ]
  },
  plugins: [
    new LicenseWebpackPlugin({
      pattern: /^(MIT|ISC|BSD.*)$/,
      addUrl: true,
      suppressErrors: true
    }),
    new Copy([
      ...buildEmbeds.map((embed) => ({
        from: path.join(__dirname, 'client', `coral-embed-${embed}`, 'style'),
        to: path.join(__dirname, 'dist', 'embed', embed)
      }))
    ]),
    autoprefixer,
    precss,
    new webpack.ProvidePlugin({
      'fetch': 'imports-loader?this=>global!exports-loader?global.fetch!whatwg-fetch'
    }),
    new webpack.DefinePlugin({
      'process.env': {
        'VERSION': `"${require('./package.json').version}"`,
      }
    }),
    new webpack.EnvironmentPlugin({
      'TALK_PLUGINS_JSON': '{}'
    })
  ],
  resolveLoader: {
    modules: ['node_modules', path.resolve(__dirname, 'client/coral-framework/loaders')],
  },
  resolve: {
    alias: {
      'plugin-api': path.resolve(__dirname, 'plugin-api/'),
      plugins: path.resolve(__dirname, 'plugins/'),
      pluginsConfig: pluginsPath
    },
    modules: [
      path.resolve(__dirname, 'plugins'),
      path.resolve(__dirname, 'client'),
      ...buildTargets.map((target) => path.join(__dirname, 'client', target, 'src')),
      ...buildEmbeds.map((embed) => path.join(__dirname, 'client', `coral-embed-${embed}`, 'src')),
      'node_modules'
    ]
  }
};

//==============================================================================
// Production configuration overrides
//==============================================================================

if (process.env.NODE_ENV === 'production') {
  config.plugins.push(new CompressionPlugin({
    asset: '[path].gz[query]',
    algorithm: 'gzip',
    test: /\.(js)$/,
    threshold: 10240,
    minRatio: 0.8
  }));
}

//==============================================================================
// Entries
//==============================================================================

// Applies the base configuration to the following entries.
const applyConfig = (entries, root = {}) => _.merge({}, config, {
  entry: entries.reduce((entry, {name, path}) => {
    entry[name] = [
      'babel-polyfill',
      path
    ];

    return entry;
  }, {})
}, root);

module.exports = [

  // Coral Embed
  applyConfig([

    // Load in the root embed.
    {
      name: 'embed',
      path: path.join(__dirname, 'client/coral-embed/src/index')
    }

  ], {
    output: {
      library: 'Coral'
    }
  }),

  // All framework targets/embeds/plugins.
  applyConfig([

    // // Load in all the targets.
    ...buildTargets.map((target) => ({
      name: `${target}/bundle`,
      path: path.join(__dirname, 'client/', target, '/src/index')
    })),

    // Load in all the embeds.
    ...buildEmbeds.map((embed) => ({
      name: `embed/${embed}/bundle`,
      path: path.join(__dirname, 'client/', `coral-embed-${embed}`, '/src/index')
    })),

    // Load in all the plugin entries.
    ...targetPlugins.reduce((entries, plugin) => {

      // Introspect the path to find a targets folder.
      let folder = path.dirname(plugin.path);
      let files = fs.readdirSync(folder);

      // While the folder does not contain the targets folder...
      while (!files.includes('targets')) {

        // Try to go up a folder.
        folder = path.normalize(path.join(folder, '..'));

        // And as long as we haven't gone too high
        if (!(folder.includes(path.join(__dirname, 'node_modules')) || !folder.includes(path.join(__dirname, 'plugins')))) {
          throw new Error(`target plugin ${plugin.name} does not have a 'targets' folder`);
        }

        files = fs.readdirSync(folder);
      }

      // List all targets available in that folder.
      folder = path.join(folder, 'targets');

      let targets = fs.readdirSync(folder);
      if (targets.length === 0) {
        throw new Error(`target plugin ${plugin.name} has no targets in it's target folder ${folder}`);
      }

      return entries.concat(targets.map((target) => ({
        name: `plugin/${plugin.name}/${target}/bundle`,
        path: path.join(folder, target, 'index')
      })));
    }, [])
  ])
];
