/*
 * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

const browserslistConfig = require('@nextcloud/browserslist-config')
const { defineConfig } = require('@rspack/cli')
const { CssExtractRspackPlugin, LightningCssMinimizerRspackPlugin, DefinePlugin, ProgressPlugin, SwcJsMinimizerRspackPlugin } = require('@rspack/core')
const NodePolyfillPlugin = require('@rspack/plugin-node-polyfill')
const browserslist = require('browserslist')
const path = require('node:path')
const { VueLoaderPlugin } = require('vue-loader')

// browserslist-rs does not support baseline queries yet
// Manually resolving the browserslist config to the list of browsers with minimal versions
// See: https://github.com/browserslist/browserslist-rs/issues/40
const browsers = browserslist(browserslistConfig)
const minBrowserVersion = browsers
	.map((str) => str.split(' '))
	.reduce((minVersion, [browser, version]) => {
		minVersion[browser] = minVersion[browser] ? Math.min(minVersion[browser], parseFloat(version)) : parseFloat(version)
		return minVersion
	}, {})
const targets = Object.entries(minBrowserVersion).map(([browser, version]) => `${browser} >=${version}`).join(',')

module.exports = defineConfig((env) => {
	const appName = process.env.npm_package_name
	const appVersion = process.env.npm_package_version

	const mode = (env.development && 'development') || (env.production && 'production') || process.env.NODE_ENV || 'production'
	const isDev = mode === 'development'
	process.env.NODE_ENV = mode

	console.info('Building', appName, appVersion, '\n')

	return {
		target: 'web',
		mode,
		devtool: isDev ? 'cheap-source-map' : 'source-map',

		entry: {
			'admin-settings': path.join(__dirname, 'src', 'mainAdminSettings.js'),
			collections: path.join(__dirname, 'src', 'collections.js'),
			main: path.join(__dirname, 'src', 'main.js'),
			recording: path.join(__dirname, 'src', 'mainRecording.js'),
			'files-sidebar': [
				path.join(__dirname, 'src', 'mainFilesSidebar.js'),
				path.join(__dirname, 'src', 'mainFilesSidebarLoader.js'),
			],
			'public-share-auth-sidebar': path.join(__dirname, 'src', 'mainPublicShareAuthSidebar.js'),
			'public-share-sidebar': path.join(__dirname, 'src', 'mainPublicShareSidebar.js'),
			flow: path.join(__dirname, 'src', 'flow.js'),
			deck: path.join(__dirname, 'src', 'deck.js'),
			maps: path.join(__dirname, 'src', 'maps.js'),
			search: path.join(__dirname, 'src', 'search.js'),
			icons: path.join(__dirname, 'src', 'icons.css'),
		},

		output: {
			path: path.resolve('./js'),
			filename: `${appName}-[name].js?v=[contenthash]`,
			chunkFilename: `${appName}-[name].js?v=[contenthash]`,
			// Set publicPath via __webpack_public_path__
			publicPath: 'auto',
			// We are working with .wasm and .tflite files as resources on a public path: it must be with the original name in the output folder's root
			assetModuleFilename: '[name][ext]?v=[contenthash]',
			// We are working with .wasm files as resources on a public path: disabling default wasm loading as source
			wasmLoading: false,
			enabledWasmLoadingTypes: [],
			clean: true,
			devtoolNamespace: appName,
			// Make sure sourcemaps have a proper path and do not leak local paths
			// Source: @nextcloud/webpack-vue-config
			devtoolModuleFilenameTemplate(info) {
				const rootDir = process.cwd()
				const rel = path.relative(rootDir, info.absoluteResourcePath)
				return `webpack:///${appName}/${rel}`
			},
		},

		devServer: {
			hot: true,
			host: '127.0.0.1',
			port: 3000,
			client: {
				overlay: false,
			},
			devMiddleware: {
				writeToDisk: true,
			},
			headers: {
				'Access-Control-Allow-Origin': '*',
			},
		},

		optimization: {
			chunkIds: 'named',
			splitChunks: {
				automaticNameDelimiter: '-',
				cacheGroups: {
					defaultVendors: {
						reuseExistingChunk: true,
					},
				},
			},
			minimize: !isDev,
			minimizer: [
				new SwcJsMinimizerRspackPlugin({
					minimizerOptions: {
						targets,
					},
				}),
				new LightningCssMinimizerRspackPlugin({
					minimizerOptions: {
						targets,
					},
				}),
			],
		},

		module: {
			rules: [
				{
					test: /\.vue$/,
					loader: 'vue-loader',
					options: {
						experimentalInlineMatchResource: true,
					},
				},
				{
					test: /\.css$/,
					use: [
						{
							loader: CssExtractRspackPlugin.loader,
						},
						'css-loader',
					],
				},
				{
					test: /\.scss$/,
					use: [
						{
							loader: CssExtractRspackPlugin.loader,
						},
						'css-loader',
						'sass-loader',
					],
				},
				{
					test: /\.ts$/,
					exclude: [/node_modules/],
					loader: 'builtin:swc-loader',
					options: {
						jsc: {
							parser: {
								syntax: 'typescript',
							},
						},
						env: {
							targets,
						},
					},
					type: 'javascript/auto',
				},
				{
					test: /\.(png|jpe?g|gif|svg|webp)$/i,
					type: 'asset',
				},
				{
					test: /\.(woff2?|eot|ttf|otf)$/i,
					type: 'asset/resource',
				},
				{
					test: /\.wasm$/i,
					type: 'asset/resource',
				},
				{
					test: /\.tflite$/i,
					type: 'asset/resource',
				},
				{
					resourceQuery: /raw/,
					type: 'asset/source',
				},
			],
		},

		plugins: [
			new ProgressPlugin(),

			new VueLoaderPlugin(),

			new NodePolyfillPlugin(),

			new DefinePlugin({
				IS_DESKTOP: false,
				__IS_DESKTOP__: false,
				appName: JSON.stringify(appName),
				appVersion: JSON.stringify(appVersion),
				// Vue compile time flags
				// See: https://vuejs.org/api/compile-time-flags.html#compile-time-flags
				// See: https://github.com/vuejs/core/blob/v3.5.24/packages/vue/README.md#bundler-build-feature-flags
				// > The build will work without configuring these flags,
				// > however it is strongly recommended to properly configure them in order to get proper tree-shaking in the final bundle
				// Unlike Vite plugin, vue-loader does not do this automatically for Webpack
				// Although documentation says, it is optional, sometimes it breaks with:
				// ReferenceError: __VUE_PROD_DEVTOOLS__ is not defined
				__VUE_OPTIONS_API__: true,
				__VUE_PROD_DEVTOOLS__: false,
				__VUE_PROD_HYDRATION_MISMATCH_DETAILS__: false,
			}),

			new CssExtractRspackPlugin({
				filename: '../css/talk-[name].css',
				chunkFilename: '../css/chunks/[id].chunk.css',
				ignoreOrder: true,
			}),
		],

		resolve: {
			extensions: ['*', '.ts', '.js', '.vue'],
			symlinks: false,
			fallback: {
				fs: false,
			},
		},

		cache: true,
	}
})
