// Copyright (c) Microsoft Corporation. All rights reserved. Licensed under the MIT license.
// See LICENSE in the project root for license information.
import * as path from 'node:path';
import * as semver from 'semver';
import { FileSystem, Import, JsonFile, MapExtensions } from '@rushstack/node-core-library';
import * as pnpmfile from './PnpmfileShim';
import { pnpmfileShimFilename, scriptsFolderPath } from '../../utilities/PathConstants';
/**
 * Loads PNPM's pnpmfile.js configuration, and invokes it to preprocess package.json files,
 * optionally utilizing a pnpmfile shim to inject preferred versions.
 */
export class PnpmfileConfiguration {
    constructor(context) {
        pnpmfile.reset();
        this._context = context;
    }
    static async initializeAsync(rushConfiguration, subspace, variant) {
        if (rushConfiguration.packageManager !== 'pnpm') {
            throw new Error(`PnpmfileConfiguration cannot be used with package manager "${rushConfiguration.packageManager}"`);
        }
        // Set the context to swallow log output and store our settings
        const context = {
            log: (message) => { },
            pnpmfileShimSettings: await PnpmfileConfiguration._getPnpmfileShimSettingsAsync(rushConfiguration, subspace, variant)
        };
        return new PnpmfileConfiguration(context);
    }
    static async writeCommonTempPnpmfileShimAsync(rushConfiguration, targetDir, subspace, variant) {
        if (rushConfiguration.packageManager !== 'pnpm') {
            throw new Error(`PnpmfileConfiguration cannot be used with package manager "${rushConfiguration.packageManager}"`);
        }
        const pnpmfilePath = path.join(targetDir, rushConfiguration.packageManagerWrapper.pnpmfileFilename);
        // Write the shim itself
        await FileSystem.copyFileAsync({
            sourcePath: `${scriptsFolderPath}/${pnpmfileShimFilename}`,
            destinationPath: pnpmfilePath
        });
        const pnpmfileShimSettings = await PnpmfileConfiguration._getPnpmfileShimSettingsAsync(rushConfiguration, subspace, variant);
        // Write the settings file used by the shim
        await JsonFile.saveAsync(pnpmfileShimSettings, path.join(targetDir, 'pnpmfileSettings.json'), {
            ensureFolderExists: true
        });
    }
    static async _getPnpmfileShimSettingsAsync(rushConfiguration, subspace, variant) {
        let allPreferredVersions = {};
        let allowedAlternativeVersions = {};
        const workspaceVersions = {};
        // Only workspaces shims in the common versions using pnpmfile
        if (rushConfiguration.packageManagerOptions.useWorkspaces) {
            const commonVersionsConfiguration = subspace.getCommonVersions(variant);
            const preferredVersions = new Map();
            MapExtensions.mergeFromMap(preferredVersions, rushConfiguration.getImplicitlyPreferredVersions(subspace, variant));
            for (const [name, version] of commonVersionsConfiguration.getAllPreferredVersions()) {
                // Use the most restrictive version range available
                if (!preferredVersions.has(name) || semver.subset(version, preferredVersions.get(name))) {
                    preferredVersions.set(name, version);
                }
            }
            allPreferredVersions = MapExtensions.toObject(preferredVersions);
            allowedAlternativeVersions = MapExtensions.toObject(commonVersionsConfiguration.allowedAlternativeVersions);
            for (const project of rushConfiguration.projects) {
                workspaceVersions[project.packageName] = project.packageJson.version;
            }
        }
        const settings = {
            allPreferredVersions,
            allowedAlternativeVersions,
            workspaceVersions,
            semverPath: Import.resolveModule({ modulePath: 'semver', baseFolderPath: __dirname })
        };
        // Use the provided path if available. Otherwise, use the default path.
        const userPnpmfilePath = subspace.getPnpmfilePath(variant);
        if (userPnpmfilePath && FileSystem.exists(userPnpmfilePath)) {
            settings.userPnpmfilePath = userPnpmfilePath;
        }
        return settings;
    }
    /**
     * Transform a package.json file using the pnpmfile.js hook.
     * @returns the transformed object, or the original input if pnpmfile.js was not found.
     */
    transform(packageJson) {
        var _a;
        if (!((_a = pnpmfile.hooks) === null || _a === void 0 ? void 0 : _a.readPackage) || !this._context) {
            return packageJson;
        }
        else {
            return pnpmfile.hooks.readPackage(packageJson, this._context);
        }
    }
}
//# sourceMappingURL=PnpmfileConfiguration.js.map