import merge from '../../utils/merge.js';
import { VITE_DEFAULT_ASSETS } from './constants.js';
import { deleteUndefinedPropertyDeeply, throwIncompatibleError } from './utils.js';
export function farmUserConfigToViteConfig(config) {
    const vitePlugins = config.vitePlugins.filter(Boolean).map((plugin) => {
        if (typeof plugin === 'function') {
            return plugin().vitePlugin;
        }
        else {
            return plugin;
        }
    });
    let sourcemap = true;
    if (config.compilation?.sourcemap !== undefined) {
        sourcemap = Boolean(config.compilation?.sourcemap);
    }
    const viteConfig = {
        root: config.root,
        base: config.compilation?.output?.publicPath ?? '/',
        publicDir: config.publicDir ?? 'public',
        mode: config.compilation?.mode,
        define: config.compilation?.define,
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore ignore this error
        command: config.compilation?.mode === 'production' ? 'build' : 'serve',
        resolve: {
            alias: config.compilation?.resolve?.alias,
            extensions: config.compilation?.resolve?.extensions,
            mainFields: config.compilation?.resolve?.mainFields,
            conditions: config.compilation?.resolve?.conditions,
            preserveSymlinks: config.compilation?.resolve?.symlinks === false
        },
        plugins: vitePlugins,
        server: {
            // eslint-disable-next-line @typescript-eslint/ban-ts-comment
            // @ts-ignore ignore error
            hmr: config.server?.hmr,
            port: config.server?.port,
            host: config.server?.host,
            strictPort: config.server?.strictPort,
            https: config.server?.https,
            proxy: config.server?.proxy,
            open: config.server?.open,
            watch: typeof config.server?.hmr === 'object'
                ? config.server.hmr?.watchOptions ?? {}
                : {}
            // other options are not supported in farm
        },
        // eslint-disable-next-line @typescript-eslint/ban-ts-comment
        // @ts-ignore ignore this error
        isProduction: config.compilation?.mode === 'production',
        css: config.compilation?.css?._viteCssOptions ?? {},
        build: {
            outDir: config.compilation?.output?.path,
            sourcemap,
            minify: config.compilation?.minify !== undefined
                ? Boolean(config.compilation?.minify)
                : undefined,
            cssMinify: config.compilation?.minify !== undefined
                ? Boolean(config.compilation?.minify)
                : undefined,
            ssr: config.compilation?.output?.targetEnv === 'node',
            rollupOptions: {
                output: {
                    assetFileNames: config.compilation?.output?.assetsFilename,
                    entryFileNames: config.compilation?.output?.entryFilename,
                    chunkFileNames: config.compilation?.output?.filename
                }
            }
            // other options are not supported in farm
        },
        // TODO make it configurable
        cacheDir: 'node_modules/.farm/cache',
        envDir: config.envDir,
        assetsInclude: [
            ...VITE_DEFAULT_ASSETS,
            ...(config.compilation?.assets?.include ?? [])
        ]
    };
    return viteConfig;
}
function getTargetField(target = {}, key, allowedKeys, contextInfo, getter) {
    if (typeof key !== 'string') {
        return target[key];
    }
    const internalKeys = ['then', 'length', 'constructor', 'prototype'];
    if (internalKeys.includes(key)) {
        return target[key];
    }
    if (allowedKeys.includes(String(key))) {
        if (getter) {
            return getter(target, key);
        }
        else {
            return target[key];
        }
    }
    throw throwIncompatibleError(contextInfo.pluginName, contextInfo.keyName, allowedKeys, key);
}
function createProxyObj(pluginName, keyName, allowedKeys, obj = {}) {
    return new Proxy(obj || {}, {
        get(target, key) {
            return getTargetField(target, key, allowedKeys, {
                pluginName,
                keyName
            });
        }
    });
}
function mapResolve(pluginName, obj = {}) {
    const allowedResolveKeys = [
        'alias',
        'extensions',
        'mainFields',
        'conditions',
        'preserveSymlinks',
        // farm do not set any thing for dedupe, it should always be undefined
        'dedupe'
    ];
    return createProxyObj(pluginName, 'viteConfig.resolve', allowedResolveKeys, obj);
}
function mapServer(pluginName, obj = {}) {
    const allowedServerKeys = [
        'hmr',
        'port',
        'host',
        'strictPort',
        'https',
        'proxy',
        'open',
        'origin',
        'watch'
    ];
    return createProxyObj(pluginName, 'viteConfig.server', allowedServerKeys, obj);
}
function mapCss(pluginName, obj = {}) {
    const allowedCssKeys = [
        'devSourcemap',
        'transformer',
        'modules',
        'postcss',
        'preprocessorOptions'
    ];
    return createProxyObj(pluginName, 'viteConfig.css', allowedCssKeys, obj);
}
function mapBuild(pluginName, obj = {}) {
    const allowedBuildKeys = [
        'outDir',
        'sourcemap',
        'minify',
        'cssMinify',
        'ssr',
        'watch',
        'rollupOptions',
        'assetsDir'
    ];
    return createProxyObj(pluginName, 'viteConfig.build', allowedBuildKeys, obj);
}
export function proxyViteConfig(viteConfig, pluginName, logger) {
    return new Proxy(viteConfig, {
        get(target, key) {
            const allowedKeys = [
                'root',
                'base',
                'publicDir',
                'mode',
                'define',
                'command',
                'resolve',
                'plugins',
                'server',
                'isProduction',
                'css',
                'build',
                'logger',
                'cacheDir',
                'envDir',
                'assetsInclude',
                // these fields are always undefined in farm
                // they are only used for compatibility
                'legacy',
                'optimizeDeps',
                'ssr',
                'logLevel',
                'experimental',
                'test',
                'clearScreen',
                'customLogger'
            ];
            return getTargetField(target, key, allowedKeys, {
                pluginName,
                keyName: 'viteConfig'
            }, (target, key) => {
                const keyMapper = {
                    resolve: mapResolve,
                    server: mapServer,
                    css: mapCss,
                    build: mapBuild,
                    optimizeDeps: (pluginName, obj = {}) => {
                        return new Proxy(obj || {}, {
                            get(_, optimizeDepsKey) {
                                logger.warnOnce(`[vite-plugin] ${pluginName}: config "optimizeDeps" is not needed in farm, all of its options will be ignored. Current ignored option is: "${String(optimizeDepsKey)}"`);
                                if (optimizeDepsKey === 'esbuildOptions') {
                                    return {};
                                }
                                return undefined;
                            }
                        });
                    },
                    logger: () => {
                        return logger;
                    },
                    assetsInclude: () => {
                        return (filename) => {
                            return (viteConfig.assetsInclude?.some((r) => {
                                return new RegExp(r).test(filename);
                            }) ?? false);
                        };
                    }
                };
                return keyMapper[key]
                    ? keyMapper[key](pluginName, target[key])
                    : target[key];
            });
        }
    });
}
export function viteConfigToFarmConfig(config, origFarmConfig, _pluginName) {
    var _a, _b, _c, _d;
    const farmConfig = {
        compilation: {}
    };
    if (config.root) {
        farmConfig.root = config.root;
    }
    if (config?.css) {
        (_a = farmConfig.compilation).css ?? (_a.css = {});
        farmConfig.compilation.css._viteCssOptions = config.css;
    }
    if (config.base) {
        (_b = farmConfig.compilation).output ?? (_b.output = {});
        farmConfig.compilation.output.publicPath = config.base;
    }
    if (config.publicDir) {
        farmConfig.publicDir = config.publicDir;
    }
    if (config.mode === 'development' || config.mode === 'production') {
        farmConfig.compilation.mode = config.mode;
    }
    if (config.define) {
        farmConfig.compilation.define = config.define;
    }
    if (config.resolve) {
        (_c = farmConfig.compilation).resolve ?? (_c.resolve = {});
        if (config.resolve.alias) {
            if (!Array.isArray(config.resolve.alias)) {
                farmConfig.compilation.resolve.alias = config.resolve.alias;
            }
            else {
                if (!farmConfig.compilation.resolve.alias) {
                    farmConfig.compilation.resolve.alias = {};
                }
                const farmRegexPrefix = '$__farm_regex:';
                for (const { find, replacement } of config.resolve.alias) {
                    if (find instanceof RegExp) {
                        const key = farmRegexPrefix + find.source;
                        farmConfig.compilation.resolve.alias[key] = replacement;
                    }
                    else {
                        farmConfig.compilation.resolve.alias[find] = replacement;
                    }
                }
            }
        }
        farmConfig.compilation.resolve.extensions = config.resolve.extensions;
        farmConfig.compilation.resolve.mainFields = config.resolve.mainFields;
        farmConfig.compilation.resolve.conditions = config.resolve.conditions;
        farmConfig.compilation.resolve.symlinks =
            config.resolve.preserveSymlinks != true;
    }
    if (config.server) {
        farmConfig.server ?? (farmConfig.server = {});
        farmConfig.server.hmr = config.server.hmr;
        farmConfig.server.port = config.server.port;
        if (config.server.watch) {
            if (farmConfig.server?.hmr === true ||
                farmConfig.server?.hmr === undefined) {
                farmConfig.server.hmr = {
                    ...(typeof origFarmConfig?.server?.hmr === 'object'
                        ? origFarmConfig.server.hmr
                        : {}),
                    watchOptions: config.server.watch
                };
            }
        }
        if (typeof config.server.host === 'string') {
            farmConfig.server.host = config.server.host;
        }
        farmConfig.server.strictPort = config.server.strictPort;
        farmConfig.server.https =
            typeof config.server.https === 'boolean'
                ? undefined
                : config.server.https;
        farmConfig.server.proxy = config.server.proxy;
        farmConfig.server.open = Boolean(config.server.open);
    }
    if (config.build) {
        (_d = farmConfig.compilation).output ?? (_d.output = {});
        farmConfig.compilation.output.path = config.build.outDir;
        if (config.build?.sourcemap !== undefined &&
            origFarmConfig.compilation?.sourcemap === undefined) {
            farmConfig.compilation.sourcemap = Boolean(config.build.sourcemap);
        }
        if (config.build.ssr !== undefined &&
            origFarmConfig.compilation?.lazyCompilation === undefined) {
            farmConfig.compilation.lazyCompilation = !config.build.ssr;
        }
        if (config.build.rollupOptions?.output !== undefined) {
            if (!Array.isArray(config.build.rollupOptions.output)) {
                const keys = ['assetFileNames', 'entryFilename', 'filename'];
                for (const k of keys) {
                    /* eslint-disable @typescript-eslint/ban-ts-comment */
                    // @ts-ignore type is correct
                    farmConfig.compilation.output[k] =
                        // @ts-ignore type is correct
                        config.build.rollupOptions.output[k];
                }
            }
        }
    }
    deleteUndefinedPropertyDeeply(farmConfig);
    return merge({}, origFarmConfig, farmConfig);
}
//# sourceMappingURL=farm-to-vite-config.js.map