import crypto from 'crypto';
import fs from 'fs';
import process from 'node:process';
import path from 'path';
import { iterateConfig } from './iterateConfig.js';
import { parsePayloadComponent } from './parsePayloadComponent.js';
export function addPayloadComponentToImportMap({ baseDir, importMap, imports, payloadComponent }) {
    if (!payloadComponent) {
        return;
    }
    const { exportName, path: componentPath } = parsePayloadComponent(payloadComponent);
    if (importMap[componentPath + '#' + exportName]) {
        return;
    }
    const importIdentifier = exportName + '_' + crypto.createHash('md5').update(componentPath).digest('hex');
    // e.g. if baseDir is /test/fields and componentPath is /components/Field.tsx
    // then path needs to be /test/fields/components/Field.tsx NOT /users/username/project/test/fields/components/Field.tsx
    // so we need to append baseDir to componentPath
    if (componentPath.startsWith('.') || componentPath.startsWith('/')) {
        const normalizedBaseDir = baseDir.replace(/\\/g, '/');
        const finalPath = normalizedBaseDir.startsWith('/../') ? `${normalizedBaseDir}${componentPath.slice(1)}` : path.posix.join(normalizedBaseDir, componentPath.slice(1));
        imports[importIdentifier] = {
            path: componentPath.startsWith('.') || componentPath.startsWith('/') ? finalPath : componentPath,
            specifier: exportName
        };
    } else {
        imports[importIdentifier] = {
            path: componentPath,
            specifier: exportName
        };
    }
    importMap[componentPath + '#' + exportName] = importIdentifier;
}
export async function generateImportMap(config, options) {
    const shouldLog = options?.log ?? true;
    if (shouldLog) {
        console.log('Generating import map');
    }
    const importMap = {};
    const imports = {};
    const rootDir = process.env.ROOT_DIR ?? process.cwd();
    // get componentsBaseDir.
    // E.g.:
    // config.admin.importMap.baseDir = /test/fields/
    // rootDir: /
    // componentsBaseDir = /test/fields/
    // or
    // E.g.:
    // config.admin.importMap.baseDir = /test/fields/
    // rootDir: /test
    // componentsBaseDir = /fields/
    // or
    // config.admin.importMap.baseDir = /
    // rootDir: /
    // componentsBaseDir = /
    // E.g.:
    // config.admin.importMap.baseDir = /test/fields/
    // rootDir: /test/fields/prod
    // componentsBaseDir = ../
    // Check if rootDir is a subdirectory of baseDir
    const baseDir = config.admin.importMap.baseDir;
    const isSubdirectory = path.relative(baseDir, rootDir).startsWith('..');
    let componentsBaseDir;
    if (isSubdirectory) {
        // Get the relative path from rootDir to baseDir
        componentsBaseDir = path.relative(rootDir, baseDir);
    } else {
        // If rootDir is not a subdirectory, just return baseDir relative to rootDir
        componentsBaseDir = `/${path.relative(rootDir, baseDir)}`;
    }
    // Ensure result has a trailing slash
    if (!componentsBaseDir.endsWith('/')) {
        componentsBaseDir += '/';
    }
    const addToImportMap = (payloadComponent)=>{
        if (!payloadComponent) {
            return;
        }
        if (typeof payloadComponent !== 'object' && typeof payloadComponent !== 'string') {
            console.error(payloadComponent);
            throw new Error('addToImportMap > Payload component must be an object or a string');
        }
        if (Array.isArray(payloadComponent)) {
            for (const component of payloadComponent){
                addPayloadComponentToImportMap({
                    baseDir: componentsBaseDir,
                    importMap,
                    imports,
                    payloadComponent: component
                });
            }
        } else {
            addPayloadComponentToImportMap({
                baseDir: componentsBaseDir,
                importMap,
                imports,
                payloadComponent
            });
        }
    };
    iterateConfig({
        addToImportMap,
        baseDir: config.admin.importMap.baseDir,
        config,
        importMap,
        imports
    });
    await writeImportMap({
        componentMap: importMap,
        fileName: 'importMap.js',
        force: options?.force,
        importMap: imports,
        log: shouldLog,
        rootDir
    });
}
export async function writeImportMap({ componentMap, fileName, force, importMap, log, rootDir }) {
    let importMapFolderPath = '';
    if (fs.existsSync(path.resolve(rootDir, 'app/(payload)/admin/'))) {
        importMapFolderPath = path.resolve(rootDir, 'app/(payload)/admin/');
    } else if (fs.existsSync(path.resolve(rootDir, 'src/app/(payload)/admin/'))) {
        importMapFolderPath = path.resolve(rootDir, 'src/app/(payload)/admin/');
    } else {
        throw new Error(`Could not find the payload admin directory. Looked in ${path.resolve(rootDir, 'app/(payload)/admin/')} and ${path.resolve(rootDir, 'src/app/(payload)/admin/')}`);
    }
    const imports = [];
    for (const [identifier, { path, specifier }] of Object.entries(importMap)){
        imports.push(`import { ${specifier} as ${identifier} } from '${path}'`);
    }
    const mapKeys = [];
    for (const [userPath, identifier] of Object.entries(componentMap)){
        mapKeys.push(`  "${userPath}": ${identifier}`);
    }
    const importMapOutputFile = `${imports.join('\n')}

export const importMap = {
${mapKeys.join(',\n')}
}
`;
    const importMapFilePath = path.resolve(importMapFolderPath, fileName);
    if (!force) {
        // Read current import map and check in the IMPORTS if there are any new imports. If not, don't write the file.
        const currentImportMap = await fs.promises.readFile(importMapFilePath, 'utf-8');
        if (currentImportMap?.trim() === importMapOutputFile?.trim()) {
            if (log) {
                console.log('No new imports found, skipping writing import map');
            }
            return;
        }
    }
    if (log) {
        console.log('Writing import map to', importMapFilePath);
    }
    await fs.promises.writeFile(importMapFilePath, importMapOutputFile);
}

//# sourceMappingURL=index.js.map