import { VitestPackageInstaller } from "vitest/node";
import node_path from "node:path";
import { fileURLToPath } from "node:url";
import { createRequire } from "../881.js";
const vitest_filename = fileURLToPath(import.meta.url);
const vitest_dirname = node_path.dirname(vitest_filename);
const vitest_require = createRequire(import.meta.url);
function testingLibraryPlugin(options) {
    const runtimeOSSPkgName = '@lynx-js/react';
    const runtimePkgName = options?.runtimePkgName ?? runtimeOSSPkgName;
    const runtimeDir = node_path.dirname(vitest_require.resolve(`${runtimePkgName}/package.json`));
    const runtimeOSSDir = node_path.dirname(vitest_require.resolve(`${runtimeOSSPkgName}/package.json`, {
        paths: [
            runtimeDir,
            vitest_dirname
        ]
    }));
    const preactDir = node_path.dirname(vitest_require.resolve('preact/package.json', {
        paths: [
            runtimeOSSDir
        ]
    }));
    const runtimeOSSAlias = generateAlias(runtimeOSSPkgName, runtimeOSSDir, runtimeDir);
    let runtimeAlias = [];
    if (runtimePkgName !== runtimeOSSPkgName) runtimeAlias = generateAlias(runtimePkgName, runtimeDir, vitest_dirname);
    const preactAlias = generateAlias('preact', preactDir, runtimeOSSDir);
    preactAlias.forEach((alias)=>{
        alias.replacement = alias.replacement.replace(/\.js$/, '.mjs');
    });
    const reactAlias = [
        {
            find: /^react$/,
            replacement: vitest_require.resolve(runtimeOSSPkgName, {
                paths: [
                    runtimeDir,
                    vitest_dirname
                ]
            })
        },
        {
            find: /^react\/jsx-runtime$/,
            replacement: vitest_require.resolve(node_path.posix.join(runtimeOSSPkgName, 'jsx-runtime'), {
                paths: [
                    runtimeDir,
                    vitest_dirname
                ]
            })
        },
        {
            find: /^react\/jsx-dev-runtime$/,
            replacement: vitest_require.resolve(node_path.posix.join(runtimeOSSPkgName, 'jsx-dev-runtime'), {
                paths: [
                    runtimeDir,
                    vitest_dirname
                ]
            })
        }
    ];
    function transformReactCompilerPlugin() {
        let rootContext, compilerDeps, babel;
        function resolveCompilerDeps(rootContext) {
            const missingBabelPackages = [];
            const [babelPath, babelPluginReactCompilerPath, babelPluginSyntaxJsxPath, babelPluginSyntaxTypescriptPath] = [
                '@babel/core',
                'babel-plugin-react-compiler',
                '@babel/plugin-syntax-jsx',
                "@babel/plugin-syntax-typescript"
            ].map((name)=>{
                try {
                    return vitest_require.resolve(name, {
                        paths: [
                            rootContext
                        ]
                    });
                } catch  {
                    missingBabelPackages.push(name);
                }
                return '';
            });
            if (missingBabelPackages.length > 0) throw new Error(`With \`experimental_enableReactCompiler\` enabled, you need to install \`${missingBabelPackages.join('`, `')}\` in your project root to use React Compiler.`);
            return {
                babelPath,
                babelPluginReactCompilerPath,
                babelPluginSyntaxJsxPath,
                babelPluginSyntaxTypescriptPath
            };
        }
        return {
            name: 'transformReactCompilerPlugin',
            enforce: 'pre',
            config (config) {
                rootContext = config.root;
                const reactCompilerRuntimeAlias = [];
                try {
                    reactCompilerRuntimeAlias.push({
                        find: /^react-compiler-runtime$/,
                        replacement: node_path.join(node_path.dirname(vitest_require.resolve('react-compiler-runtime/package.json', {
                            paths: [
                                rootContext
                            ]
                        })), 'src', 'index.ts')
                    });
                } catch (e) {}
                let mergedAlias = [
                    ...reactCompilerRuntimeAlias
                ];
                if (config.test?.alias) mergedAlias = Array.isArray(config.test.alias) ? [
                    ...config.test.alias,
                    ...mergedAlias
                ] : [
                    ...Object.entries(config.test.alias).map(([key, value])=>({
                            find: key,
                            replacement: value
                        })),
                    ...mergedAlias
                ];
                config.test = config.test || {};
                config.test.alias = mergedAlias;
                compilerDeps = resolveCompilerDeps(rootContext);
                const { babelPath } = compilerDeps;
                babel = vitest_require(babelPath);
            },
            async transform (sourceText, sourcePath) {
                if (/\.(?:jsx|tsx)$/.test(sourcePath)) {
                    const { babelPluginReactCompilerPath, babelPluginSyntaxJsxPath, babelPluginSyntaxTypescriptPath } = compilerDeps;
                    const isTSX = sourcePath.endsWith('.tsx');
                    try {
                        const result = babel.transformSync(sourceText, {
                            plugins: [
                                [
                                    babelPluginReactCompilerPath,
                                    {
                                        target: '17'
                                    }
                                ],
                                babelPluginSyntaxJsxPath,
                                isTSX ? [
                                    babelPluginSyntaxTypescriptPath,
                                    {
                                        isTSX: true
                                    }
                                ] : null
                            ].filter(Boolean),
                            filename: sourcePath,
                            ast: false,
                            sourceMaps: true
                        });
                        if (result?.code != null && result?.map != null) return {
                            code: result.code,
                            map: result.map
                        };
                        this.error(`babel-plugin-react-compiler transform failed for ${sourcePath}: ${result ? 'missing code or map' : 'no result'}`);
                    } catch (e) {
                        this.error(e);
                    }
                }
                return null;
            }
        };
    }
    let config;
    function transformReactLynxPlugin() {
        return {
            name: 'transformReactLynxPlugin',
            enforce: 'pre',
            async buildStart () {
                await ensurePackagesInstalled();
            },
            transform (sourceText, sourcePath) {
                const id = sourcePath;
                const regex = /\.(?:js|jsx|mjs|cjs|ts|tsx|mts|cts)(\?.*)?$/;
                if (!regex.test(id)) return null;
                const { transformReactLynxSync } = vitest_require('@lynx-js/react/transform');
                const relativePath = normalizeSlashes(node_path.relative(config.root, sourcePath));
                const basename = node_path.basename(sourcePath);
                const result = transformReactLynxSync(sourceText, {
                    mode: 'test',
                    pluginName: '',
                    filename: basename,
                    sourcemap: true,
                    snapshot: {
                        preserveJsx: false,
                        runtimePkg: `${runtimePkgName}/internal`,
                        jsxImportSource: runtimePkgName,
                        filename: relativePath,
                        target: 'MIXED'
                    },
                    engineVersion: options?.engineVersion ?? '',
                    dynamicImport: {
                        injectLazyBundle: false,
                        layer: 'test',
                        runtimePkg: `${runtimePkgName}/internal`
                    },
                    directiveDCE: false,
                    defineDCE: false,
                    shake: false,
                    compat: false,
                    worklet: {
                        filename: relativePath,
                        runtimePkg: `${runtimePkgName}/internal`,
                        target: 'MIXED'
                    },
                    refresh: false,
                    cssScope: false
                });
                if (result.errors.length > 0) result.errors.forEach((error)=>{
                    this.error(error.text ?? 'Unknown error', {
                        line: 1,
                        column: 1,
                        ...error.location
                    });
                });
                if (result.warnings.length > 0) result.warnings.forEach((warning)=>{
                    this.warn(warning.text ?? 'Unknown warning', {
                        line: 1,
                        column: 1,
                        ...warning.location
                    });
                });
                return {
                    code: result.code,
                    map: result.map
                };
            },
            config: ()=>({
                    test: {
                        environment: vitest_require.resolve(`${runtimeOSSDir}/testing-library/dist/env/vitest`),
                        globals: true,
                        setupFiles: [
                            vitest_require.resolve('../setupFiles/vitest')
                        ],
                        alias: [
                            ...runtimeOSSAlias,
                            ...runtimeAlias,
                            ...preactAlias,
                            ...reactAlias
                        ]
                    }
                }),
            configResolved (_config) {
                config = _config;
            }
        };
    }
    return [
        ...options?.experimental_enableReactCompiler ? [
            transformReactCompilerPlugin()
        ] : [],
        transformReactLynxPlugin()
    ];
}
async function ensurePackagesInstalled() {
    const installer = new VitestPackageInstaller();
    const installed = await installer.ensureInstalled('jsdom', process.cwd());
    if (!installed) {
        console.log('ReactLynx Testing Library requires jsdom to be installed.');
        process.exit(1);
    }
}
function generateAlias(pkgName, pkgDir, resolveDir) {
    const pkgExports = vitest_require(node_path.join(pkgDir, 'package.json')).exports;
    if (!pkgExports || 'object' != typeof pkgExports) return [];
    const pkgAlias = [];
    Object.keys(pkgExports).forEach((key)=>{
        const name = node_path.posix.join(pkgName, key);
        const escapedName = name.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
        pkgAlias.push({
            find: new RegExp('^' + escapedName + '$'),
            replacement: vitest_require.resolve(name, {
                paths: [
                    resolveDir,
                    vitest_dirname
                ]
            })
        });
    });
    return pkgAlias;
}
function normalizeSlashes(file) {
    return file.replaceAll(node_path.win32.sep, '/');
}
export { testingLibraryPlugin as vitestTestingLibraryPlugin };
