// Copyright (C) 2020-2022 Intel Corporation
// Copyright (C) CVAT.ai Corporation
//
// SPDX-License-Identifier: MIT

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const CopyPlugin = require('copy-webpack-plugin');

module.exports = (env) => {
    const defaultAppConfig = path.join(__dirname, 'src/config.tsx');
    const defaultPlugins = ['plugins/sam'];

    const sourceMapsDisabled = (process.env.DISABLE_SOURCE_MAPS || 'false').toLocaleLowerCase() === 'true';
    const appConfigFile = process.env.UI_APP_CONFIG ? process.env.UI_APP_CONFIG : defaultAppConfig;
    const pluginsList = process.env.CLIENT_PLUGINS ? [...defaultPlugins, ...process.env.CLIENT_PLUGINS.split(':')]
        .map((s) => s.trim()).filter((s) => !!s) : defaultPlugins;
    const sourceMapsToken = process.env.SOURCE_MAPS_TOKEN || '';

    const transformedPlugins = pluginsList
        .filter((plugin) => !!plugin).reduce((acc, _path, index) => ({
            ...acc,
            [`plugin_${index}`]: {
                dependOn: 'cvat-ui',
                // path can be absolute, in this case it is accepted as is
                // also the path can be relative to cvat-ui root directory
                import: path.isAbsolute(_path) ? _path : path.join(__dirname, _path, 'src', 'ts', 'index.tsx'),
            },
        }), {});

    console.log('Source maps: ', sourceMapsDisabled ? 'disabled' : 'enabled');
    console.log('List of plugins: ', Object.values(transformedPlugins).map((plugin) => plugin.import));

    const host = process.env.CVAT_UI_HOST ?? 'localhost';
    const port = process.env.CVAT_UI_PORT ?? 3000;
    return {
        target: 'web',
        mode: 'production',
        devtool: sourceMapsDisabled ? false : 'source-map',
        entry: {
            'cvat-ui': './src/index.tsx',
            ...transformedPlugins,
        },
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: 'assets/[name].[contenthash].min.js',
            publicPath: '/',
        },
        devServer: {
            host,
            port,
            compress: false,
            client: {
                overlay: false,
                webSocketURL: 'ws://0.0.0.0:0/ws',
            },
            historyApiFallback: true,
            static: {
                directory: path.join(__dirname, 'dist'),
            },
            headers: {
                // to enable SharedArrayBuffer and ONNX multithreading
                // https://cloudblogs.microsoft.com/opensource/2021/09/02/onnx-runtime-web-running-your-machine-learning-model-in-browser/
                'Cross-Origin-Opener-Policy': 'same-origin',
                'Cross-Origin-Embedder-Policy': 'credentialless',
            },
            proxy: [{
                context: (param) =>
                    param.match(
                        /\/api\/.*|analytics\/.*|static\/.*|admin(?:\/(.*))?.*|profiler(?:\/(.*))?.*|documentation\/.*|django-rq(?:\/(.*))?/gm,
                    ),
                target: env && env.API_URL,
                secure: false,
                changeOrigin: true,
                onProxyReq: (proxyReq) => {
                    proxyReq.setHeader('X-FORWARDED-HOST', `${host}:${port}`);
                },
            }],
        },
        resolve: {
            extensions: ['.tsx', '.ts', '.jsx', '.js', '.json'],
            fallback: {
                fs: false,
            },
            alias: {
                config$: appConfigFile,

                // when import svg modules
                // the loader transforms their to modules with JSX code
                // and adds 'import React from "react";'
                // in plugins it leads to errors because they must import '@modules/react'
                // so, this alias added to fix it
                react: '@modules/react',
                '@root': path.resolve(__dirname, 'src'),
                '@modules': path.resolve(__dirname, '..', 'node_modules'),
            },
            modules: [path.resolve(__dirname, 'src'), 'node_modules'],
        },
        module: {
            rules: [
                {
                    test: /\.(ts|tsx)$/,
                    use: {
                        loader: 'babel-loader',
                        options: {
                            plugins: [
                                '@babel/plugin-proposal-class-properties',
                                '@babel/plugin-proposal-optional-chaining',
                                [
                                    'import',
                                    {
                                        libraryName: 'antd',
                                    },
                                ],
                            ],
                            presets: ['@babel/preset-env', '@babel/preset-react', '@babel/typescript'],
                            sourceType: 'unambiguous',
                        },
                    },
                },
                {
                    test: /\.(css|scss)$/,
                    use: [
                        'style-loader',
                        {
                            loader: 'css-loader',
                            options: {
                                importLoaders: 2,
                            },
                        },
                        {
                            loader: 'postcss-loader',
                            options: {
                                postcssOptions: {
                                    plugins: [
                                        [
                                            'postcss-preset-env', {},
                                        ],
                                    ],
                                },
                            },
                        },
                        'sass-loader',
                    ],
                },
                {
                    test: /\.svg$/,
                    exclude: /node_modules/,
                    use: [
                        'babel-loader',
                        {
                            loader: 'react-svg-loader',
                            options: {
                                svgo: {
                                    plugins: [{ pretty: true }, { cleanupIDs: false }],
                                },
                            },
                        },
                    ],
                },
                {
                    test: /\.(png|jpg|jpeg|gif)$/i,
                    type: 'asset/resource',
                },
            ],
            parser: {
                javascript: {
                    exportsPresence: 'error',
                },
            },
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: './src/index.html',
                inject: 'body',
            }),
            new Dotenv({
                systemvars: true,
            }),
            new CopyPlugin({
                patterns: [
                    {
                        from: '../cvat-data/src/ts/3rdparty/avc.wasm',
                        to: 'assets/3rdparty/',
                    },
                    {
                        from: '../node_modules/onnxruntime-web/dist/*.wasm',
                        to  : 'assets/[name][ext]',
                    },
                    {
                        from: 'src/assets/opencv_4.8.0.js',
                        to  : 'assets/opencv_4.8.0.js',
                    },
                    {
                        from: 'src/assets/*.png',
                        to  : 'assets/[name][ext]',
                    },
                    {
                        from: 'plugins/**/assets/*.(onnx|js)',
                        to  : 'assets/[name][ext]',
                    }
                ],
            }),
            ...(!sourceMapsDisabled && sourceMapsToken ? [new webpack.SourceMapDevToolPlugin({
                append: '\n',
                filename: `${sourceMapsToken}/[file].map`,
            })] : []),
        ],
    }
};
