import type { Contexts } from "@devowl-wp/freemium/webpack";
import {
    applyFreemiumConfigOverride,
    applyFreemiumDefinePlugin,
    applyFreemiumWebpackBarOptions,
} from "@devowl-wp/freemium/webpack";
import type { FactoryValues } from "@devowl-wp/webpack-config";
import {
    InlineRequirePlugin,
    SimpleEntryChunksPlugin,
    applyAntdDefinePlugin,
    applyPreact,
    createDefaultSettings,
} from "@devowl-wp/webpack-config";

import type { Configuration } from "webpack";

const ANTD_PREFIX = "rcb-antd";
const { TCF_CMP_ID } = process.env;

const sideEffectFree = [/node_modules\/@iabtechlabtcf\/(core|cmpapi)/];

const commonBannerOptions: Partial<Parameters<typeof createDefaultSettings>[2]> = {
    skipExternals: ["@devowl-wp/utils", "react", "react-dom", "react/jsx-runtime", "react/jsx-dev-runtime"],
    onlyEntrypoints: ["banner", "blocker"],
    sideEffectFree,
    writeStats: true,
    replaceWithEmptyModule: ["json-form-data"],
};

const commonBannerOverrideConfig = (
    pluginContext: Contexts,
    config: Configuration,
    factoryValues: FactoryValues,
    { maxSizeKb }: { maxSizeKb: number },
) => {
    applyFreemiumConfigOverride(pluginContext, config);
    applyPreact(config);

    config.plugins.push(new InlineRequirePlugin());
    config.plugins.push(new SimpleEntryChunksPlugin());

    if (factoryValues.mode === "production") {
        config.performance = {
            ...config.performance,
            hints: "error",
            maxAssetSize: maxSizeKb * 1024,
        };
    }

    // Do never create other chunks
    const { splitChunks } = config.optimization;
    if (splitChunks) {
        const { cacheGroups } = splitChunks;
        cacheGroups.default = false;
        cacheGroups.defaultVendors = false;

        // Create only one level of chunks, as the cookie banner always need to be loaded early
        // and we do not need to have unnecessary amount of chunks.
        cacheGroups.vendorCommonAsync = {
            test: /node_modules.*(?<!\.css)(?<!\.scss)(?<!\.less)$/,
            name: `${(cacheGroups.vendor as any).name}-common-async`,
            chunks: "async",
            minChunks: 2,
            priority: 25,
            reuseExistingChunk: true,
        };
        cacheGroups.commonAsync = {
            name: `${(cacheGroups.vendor as any).name.substring("vendor-".length)}-common-async`,
            chunks: "async",
            minChunks: 2,
            priority: 0,
            reuseExistingChunk: true,
        };
    }

    config.output.chunkFilename = `${config.name}-${config.output.chunkFilename}`;
};

function createContextSettings(pluginContext: Contexts) {
    return createDefaultSettings(import.meta.filename, "plugin", {
        skipExternals: ["@devowl-wp/multilingual"],
        skipEntrypoints: ["banner", "blocker"],
        sideEffectFree,
        override: ([config]) => {
            applyFreemiumConfigOverride(pluginContext, config);

            Object.assign(config.externals, {
                moment: "moment",
                "moment-timezone": "moment",
                codemirror: "CodeMirror",
            });
        },
        definePlugin: (processEnv) => {
            applyFreemiumDefinePlugin(pluginContext, processEnv);
            applyAntdDefinePlugin(ANTD_PREFIX, processEnv);
            processEnv.IS_TCF = JSON.stringify("1"); // Also include TCF so it works in banner preview (List of consents)
            processEnv.TCF_CMP_ID = TCF_CMP_ID;
            return processEnv;
        },
        webpackBarOptions: (options) => {
            applyFreemiumWebpackBarOptions(pluginContext, options);
            return options;
        },
    })
        .concat(
            // Create an own bundle for banner / blocker without any other dependencies as externals, bundle all together
            createDefaultSettings(import.meta.filename, "plugin", {
                // Bundle analyzer should only be manually enabled for debugging purposes
                // bundleAnalyzerOptions: pluginContext === "pro" && process.env.NODE_ENV !== "production",
                ...commonBannerOptions,
                forceFrontendChunks: "banner",
                override: ([config], factoryValues) => {
                    config.name = "banner";

                    commonBannerOverrideConfig(pluginContext, config, factoryValues, {
                        maxSizeKb: 400,
                    });

                    const entry = config.entry as any;
                    entry.blocker = {
                        import: entry.blocker,
                        dependOn: "banner",
                    };
                },
                definePlugin: (processEnv) => {
                    applyFreemiumDefinePlugin(pluginContext, processEnv);
                    applyAntdDefinePlugin(ANTD_PREFIX, processEnv);
                    processEnv.IS_TCF = JSON.stringify("0");
                    processEnv.TCF_CMP_ID = TCF_CMP_ID;
                    return processEnv;
                },
                webpackBarOptions: (options) => {
                    applyFreemiumWebpackBarOptions(pluginContext, options);
                    options.name = `${options.name}-banner.js`;
                    return options;
                },
            }),
        )
        .concat(
            // Create an own bundle for the TCF banner
            pluginContext === "pro"
                ? createDefaultSettings(import.meta.filename, "plugin", {
                      ...commonBannerOptions,
                      forceFrontendChunks: "banner_tcf",
                      override: ([config], factoryValues) => {
                          config.name = "banner_tcf";

                          commonBannerOverrideConfig(pluginContext, config, factoryValues, {
                              maxSizeKb: 400,
                          });

                          const entry = config.entry as any;
                          config.entry = {
                              banner_tcf: [entry.banner],
                              blocker_tcf: {
                                  import: entry.blocker,
                                  dependOn: "banner_tcf",
                              },
                          };
                      },
                      definePlugin: (processEnv) => {
                          applyFreemiumDefinePlugin(pluginContext, processEnv);
                          applyAntdDefinePlugin(ANTD_PREFIX, processEnv);
                          processEnv.IS_TCF = JSON.stringify("1");
                          processEnv.TCF_CMP_ID = TCF_CMP_ID;
                          return processEnv;
                      },
                      webpackBarOptions: (options) => {
                          applyFreemiumWebpackBarOptions(pluginContext, options);
                          options.name = `${options.name}-banner-tcf.js`;
                          return options;
                      },
                  })
                : [],
        );
}

export default [createContextSettings("lite"), createContextSettings("pro")].flat();
