const HtmlWebpackPlugin = require("html-webpack-plugin")
const HtmlWebpackDeployPlugin = require("html-webpack-deploy-plugin")
const path = require("path")
const { VueLoaderPlugin } = require("vue-loader")
const ZipPlugin = require("zip-webpack-plugin")

const TerserPlugin = require("terser-webpack-plugin")
const MiniCssExtractPlugin = require("mini-css-extract-plugin")

module.exports = (env, argv) => {
	const isDev = argv.mode === "development";

	const entry = path.resolve(__dirname, "src/index.ts")

	let devtool = false;

	const output = {
		path: path.resolve(__dirname, "dist"),
		clean: true
	}

	output.publicPath = ""
	const externals = {
		"vue": "Vue",
		"@arcadash/interop"          : "Arca$Interop"  ,
		"@arcadash/components"    : "Arca$Component",
		"@arcadash/commons": "Arca$Commons"  ,
	}

	const lessConfig = [
		{
			loader: "css-loader",
			options: {
				importLoaders: 1
			}
		},
		{
			loader: "less-loader",
			options: {
				additionalData: `@import (reference) "~@/Styles/lib.d.less";`
			}
		}
	]
	const module = {
		rules: [
			{
				test: /[\\/]commons[\\/].+/,
				exclude: /\.(js|less)$/,

				type: "asset/resource",
				generator: {
					/**
					 * @param {{filename: string}} pathData
					 * @param {import("webpack").AssetInfo} assetInfo 
					 * @returns 
					 */
					filename: (pathData, assetInfo) => {
						const fromSlice = "commons";
						const from = pathData.filename.indexOf(fromSlice) + fromSlice.length + 1;
						const to = pathData.filename.lastIndexOf("/") || pathData.filename.lastIndexOf("\\");
						
						return `Commons2/${pathData.filename.slice(from, to)}/[name][ext]`;
					}
				}
			},
			{
				test: /\@arcadash[\\/]widgets[\\/].+/,

				type: "asset/resource",
				generator: {
					/**
					 * @param {{filename: string}} pathData
					 * @param {import("webpack").AssetInfo} assetInfo 
					 * @returns 
					 */
					filename: (pathData, assetInfo) => {
						const from = pathData.filename.indexOf("dist") + 5;
						const to = pathData.filename.lastIndexOf("/") || pathData.filename.lastIndexOf("\\");
						
						return `./Widgets/${pathData.filename.slice(from, to)}/[name][ext]`;
					}
				}
			},
			{
				test: /\.[tj]s$/,
				loader: "babel-loader",
				options: {
					cacheDirectory: true
				}
			},
			{
				test: /\.vue$/,
				loader: "vue-loader",
				options: {
					cacheDirectory: path.resolve(__dirname, ".cache/vue"),
					cacheIdentifier: "vue"
				}
			},
			{
				test: /\.less$/,
				oneOf: [
					{
						use: [
							MiniCssExtractPlugin.loader,
							...lessConfig
						]
					}
				]
			}
		]
	}
	
	const watchOptions = {
		followSymlinks: true
	}

	const resolve = {
		modules: [path.resolve(__dirname, "../../node_modules"), "node_modules"],
		extensions: [".ts", ".js"],
		alias: {
			"@": path.resolve(__dirname, "src")
		}
	}
	if (!isDev) {
		resolve.alias[path.resolve(__dirname, "src/handler.ts")] = path.resolve(__dirname, "src/handler.null.ts");
	}

	const commonHtmlInjectOptions = {
		append: false,
		getPackagePath: (name, ver, pPath) => path.join(name, pPath),
		packagesPath: "Commons2/Libraries"
	}
	const plugins = [
		new VueLoaderPlugin(),
		new HtmlWebpackPlugin({
			template: path.resolve(__dirname, "src/index.html"),
		}),
		new HtmlWebpackDeployPlugin({
			...commonHtmlInjectOptions,

			packages: {
				"vue-code-highlight": {
					copy: [{ from: "themes/prism-solarizedlight.css", to: "vue-code-theme.css" }],
					links: { path: "vue-code-theme.css" }
				},
				"@arcadash/interop": {
					copy: [{ from: "dist/main.js", to: "interop.js" }],
					scripts: { path: "interop.js" },
				},
				"vue": {
					copy: [{ from: isDev ? "dist/vue.js" : "dist/vue.runtime.min.js", to: "vue.js" }],
					scripts: { path: "vue.js" }
				},
				"@arcadash/commons": {
					copy: [{ from: "dist/main.js", to: "commons.js" }],
					scripts: { path: "commons.js" }
				},
				"@arcadash/components": {
					copy: [
						{ from: "dist/main.js" , to: "components.js"  },
						{ from: "dist/main.css", to: "components.css" },
					],
					scripts: { path: "components.js"  },
					links  : { path: "components.css" }
				}
			}
		}),
		// For some reason when multiple HtmlWebpackDeployPlugin specify the option append: false,
		// the second one is injected before the first one...
		new HtmlWebpackDeployPlugin({
			...commonHtmlInjectOptions,

			packages: {
				"@arcadash/commons": {
					copy: [{ from: "dist/polyfills.js", to: "polyfills.js" }],
					scripts: { path: "polyfills.js" }
				},
			}
		}),
		new MiniCssExtractPlugin({
			filename: "main.css"
		}),
	]
	if (!isDev)
		plugins.push(
			new ZipPlugin({
				path: path.resolve(__dirname, "artifacts"),
				filename: `dist.${Date.now()}.zip`
			})
		)

	const performance = {
		hints: false
	}
	const optimization = {
		emitOnErrors: false,
		minimize: false
	}

	return {
		entry,
		output,

		devtool,

		watchOptions,
	
		externals,
	
		module,
	
		resolve,
	
		plugins,
	
		performance,
		optimization
	}
}