/**
 * React Starter Kit (https://www.reactstarterkit.com/)
 *
 * Copyright © 2014-present Kriasoft, LLC. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

import path from 'path';
import webpack from 'webpack';
import AssetsPlugin from 'assets-webpack-plugin';
import {BundleAnalyzerPlugin} from 'webpack-bundle-analyzer';
import pkg from '../package.json';

const isDebug = !process.argv.includes('--release');
const isVerbose = process.argv.includes('--verbose');
const isAnalyze = process.argv.includes('--analyze') || process.argv.includes('--analyse');

//
// Common configuration chunk to be used for both
// client-side (client.js) and server-side (server.js) bundles
// -----------------------------------------------------------------------------

const config = {
	context: path.resolve(__dirname, '..'),

	output: {
		path: path.resolve(__dirname, '../build/public/assets'),
		publicPath: '/assets/',
		pathinfo: isVerbose,
	},

	module: {
		rules: [
			{
				test: /\.jsx?$/,
				loader: 'babel-loader',
				include: [
					path.resolve(__dirname, '../src'),
				],
				query: {
					// https://github.com/babel/babel-loader#options
					cacheDirectory: isDebug,

					// https://babeljs.io/docs/usage/options/
					babelrc: false,
					presets: [
						// A Babel preset that can automatically determine the Babel plugins and polyfills
						// https://github.com/babel/babel-preset-env
						['env', {
							targets: {
								browsers: pkg.browserslist,
							},
							modules: false,
							useBuiltIns: false,
							debug: false,
						}],
						// Experimental ECMAScript proposals
						// https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets-
						'stage-2',
						// JSX, Flow
						// https://github.com/babel/babel/tree/master/packages/babel-preset-react
						'react',
						// Optimize React code for the production build
						// https://github.com/thejameskyle/babel-react-optimize
						...isDebug ? [] : ['react-optimize'],
					],
					plugins: [
						// Adds component stack to warning messages
						// https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-source
						...isDebug ? ['transform-react-jsx-source'] : [],
						// Adds __self attribute to JSX which React will use for some warnings
						// https://github.com/babel/babel/tree/master/packages/babel-plugin-transform-react-jsx-self
						...isDebug ? ['transform-react-jsx-self'] : [],
					],
				},
			},
			{
				test: /\.css/,
				use: [
					{
						loader: 'isomorphic-style-loader',
					},
					{
						loader: 'css-loader',
						options: {
							// CSS Loader https://github.com/webpack/css-loader
							importLoaders: 1,
							sourceMap: isDebug,
							// CSS Modules https://github.com/css-modules/css-modules
							modules: true,
							localIdentName: isDebug ? '[name]-[local]-[hash:base64:5]' : '[hash:base64:5]',
							// CSS Nano http://cssnano.co/options/
							minimize: !isDebug,
							discardComments: {removeAll: true},
						},
					},
					{
						loader: 'postcss-loader',
						options: {
							config: './tools/postcss.config.js',
						},
					},
				],
			},
			{
				test: /\.scss$/,
				use: [
					{
						loader: 'isomorphic-style-loader',
					},
					{
						loader: 'css-loader',
						options: {
							sourceMap: isDebug,
							minimize: !isDebug,
						}
					},
					{
						loader: 'postcss-loader',
						options: {
							config: './tools/postcss.sass.js',
						}
					},
					{
						loader: 'sass-loader',
					}
				]
			},
			{
				test: /\.md$/,
				loader: path.resolve(__dirname, './lib/markdown-loader.js'),
			},
			{
				test: /\.txt$/,
				loader: 'raw-loader',
			},
			{
				test: /\.(ico|jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
				loader: 'file-loader',
				query: {
					name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]',
				},
			},
			{
				test: /\.(mp4|webm|wav|mp3|m4a|aac|oga)(\?.*)?$/,
				loader: 'url-loader',
				query: {
					name: isDebug ? '[path][name].[ext]?[hash:8]' : '[hash:8].[ext]',
					limit: 10000,
				},
			},
		],
	},

	// Don't attempt to continue if there are any errors.
	bail: !isDebug,

	cache: isDebug,

	stats: {
		colors: true,
		reasons: isDebug,
		hash: isVerbose,
		version: isVerbose,
		timings: true,
		chunks: isVerbose,
		chunkModules: isVerbose,
		cached: isVerbose,
		cachedAssets: isVerbose,
	},
};

//
// Configuration for the client-side bundle (client.js)
// -----------------------------------------------------------------------------

const clientConfig = {
	...config,

	name: 'client',
	target: 'web',

	entry: {
		client: ['babel-polyfill', './src/client.js'],
	},

	output: {
		...config.output,
		filename: isDebug ? '[name].js' : '[name].[chunkhash:8].js',
		chunkFilename: isDebug ? '[name].chunk.js' : '[name].[chunkhash:8].chunk.js',
	},

	plugins: [
		// Define free variables
		// https://webpack.github.io/docs/list-of-plugins.html#defineplugin
		new webpack.DefinePlugin({
			'process.env.NODE_ENV': isDebug ? '"development"' : '"production"',
			'process.env.BROWSER': true,
			__DEV__: isDebug,
		}),

		// Emit a file with assets paths
		// https://github.com/sporto/assets-webpack-plugin#options
		new AssetsPlugin({
			path: path.resolve(__dirname, '../build'),
			filename: 'assets.json',
			prettyPrint: true,
		}),

		// Move modules that occur in multiple entry chunks to a new entry chunk (the commons chunk).
		// http://webpack.github.io/docs/list-of-plugins.html#commonschunkplugin
		new webpack.optimize.CommonsChunkPlugin({
			name: 'vendor',
			minChunks: module => /node_modules/.test(module.resource),
		}),

		...isDebug ? [] : [
				// Minimize all JavaScript output of chunks
				// https://github.com/mishoo/UglifyJS2#compressor-options
				new webpack.optimize.UglifyJsPlugin({
					sourceMap: true,
					compress: {
						screw_ie8: true, // React doesn't support IE8
						warnings: isVerbose,
						unused: true,
						dead_code: true,
					},
					mangle: {
						screw_ie8: true,
					},
					output: {
						comments: false,
						screw_ie8: true,
					},
				}),
			],

		// Webpack Bundle Analyzer
		// https://github.com/th0r/webpack-bundle-analyzer
		...isAnalyze ? [new BundleAnalyzerPlugin()] : [],
	],

	// Choose a developer tool to enhance debugging
	// http://webpack.github.io/docs/configuration.html#devtool
	devtool: isDebug ? 'cheap-module-source-map' : false,

	// Some libraries import Node modules but don't use them in the browser.
	// Tell Webpack to provide empty mocks for them so importing them works.
	// https://webpack.github.io/docs/configuration.html#node
	// https://github.com/webpack/node-libs-browser/tree/master/mock
	node: {
		fs: 'empty',
		net: 'empty',
		tls: 'empty',
	},
};

//
// Configuration for the server-side bundle (server.js)
// -----------------------------------------------------------------------------

const serverConfig = {
	...config,

	name: 'server',
	target: 'node',

	entry: {
		server: ['babel-polyfill', './src/server.js'],
	},

	output: {
		...config.output,
		filename: '../../server.js',
		libraryTarget: 'commonjs2',
	},

	module: {
		...config.module,

		// Override babel-preset-env configuration for Node.js
		rules: config.module.rules.map(rule => (rule.loader !== 'babel-loader' ? rule : {
				...rule,
				query: {
					...rule.query,
					presets: rule.query.presets.map(preset => (preset[0] !== 'env' ? preset : ['env', {
							targets: {
								node: parseFloat(pkg.engines.node.replace(/^\D+/g, '')),
							},
							modules: false,
							useBuiltIns: false,
							debug: false,
						}])),
				},
			})),
	},

	externals: [
		/^\.\/assets\.json$/,
		(context, request, callback) => {
			const isExternal =
				request.match(/^[@a-z][a-z/.\-0-9]*$/i) && !request.match(/\.(css|less|scss|sss)$/i);
			callback(null, Boolean(isExternal));
		},
	],

	plugins: [
		// Define free variables
		// https://webpack.github.io/docs/list-of-plugins.html#defineplugin
		new webpack.DefinePlugin({
			'process.env.NODE_ENV': isDebug ? '"development"' : '"production"',
			'process.env.BROWSER': false,
			__DEV__: isDebug,
		}),

		// Do not create separate chunks of the server bundle
		// https://webpack.github.io/docs/list-of-plugins.html#limitchunkcountplugin
		new webpack.optimize.LimitChunkCountPlugin({maxChunks: 1}),

		// Adds a banner to the top of each generated chunk
		// https://webpack.github.io/docs/list-of-plugins.html#bannerplugin
		new webpack.BannerPlugin({
			banner: 'require("source-map-support").install();',
			raw: true,
			entryOnly: false,
		}),
	],

	node: {
		console: false,
		global: false,
		process: false,
		Buffer: false,
		__filename: false,
		__dirname: false,
	},

	devtool: isDebug ? 'cheap-module-source-map' : 'source-map',
};

export default [clientConfig, serverConfig];
