"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const p_limit_1 = require("p-limit");
const path = require("path");
const pathAbsolute = require("path-absolute");
const R = require("ramda");
const supi_1 = require("supi");
const createStoreController_1 = require("../createStoreController");
const findWorkspacePackages_1 = require("../findWorkspacePackages");
const getConfigs_1 = require("../getConfigs");
const readImporterManifest_1 = require("../readImporterManifest");
const installLimit = p_limit_1.default(4);
exports.default = async (input, opts) => {
    const cwd = opts && opts.prefix || process.cwd();
    const storeControllerCache = new Map();
    let workspacePackages;
    let localPackages;
    if (opts.linkWorkspacePackages && opts.workspacePrefix) {
        workspacePackages = await findWorkspacePackages_1.default(opts.workspacePrefix, opts);
        localPackages = findWorkspacePackages_1.arrayOfLocalPackagesToMap(workspacePackages);
    }
    else {
        localPackages = {};
    }
    const store = await createStoreController_1.cached(storeControllerCache, opts);
    const linkOpts = Object.assign(opts, {
        localPackages,
        store: store.path,
        storeController: store.ctrl,
    });
    // pnpm link
    if (!input || !input.length) {
        const { manifest, writeImporterManifest } = await readImporterManifest_1.tryReadImporterManifest(opts.globalPrefix, opts);
        const newManifest = await supi_1.linkToGlobal(cwd, Object.assign({}, linkOpts, { manifest: manifest || {} }));
        await writeImporterManifest(newManifest);
        return;
    }
    const [pkgPaths, pkgNames] = R.partition((inp) => inp.startsWith('.'), input);
    if (pkgNames.length) {
        let globalPkgNames;
        if (opts.workspacePrefix) {
            workspacePackages = await findWorkspacePackages_1.default(opts.workspacePrefix, opts);
            const pkgsFoundInWorkspace = workspacePackages.filter((pkg) => pkgNames.includes(pkg.manifest.name));
            pkgsFoundInWorkspace.forEach((pkgFromWorkspace) => pkgPaths.push(pkgFromWorkspace.path));
            if (pkgsFoundInWorkspace.length && !linkOpts.saveDev && !linkOpts.saveProd && !linkOpts.saveOptional) {
                linkOpts.saveProd = true;
            }
            globalPkgNames = pkgNames.filter((pkgName) => !pkgsFoundInWorkspace.some((pkgFromWorkspace) => pkgFromWorkspace.manifest.name === pkgName));
        }
        else {
            globalPkgNames = pkgNames;
        }
        const globalPkgPath = pathAbsolute(opts.globalPrefix);
        globalPkgNames.forEach((pkgName) => pkgPaths.push(path.join(globalPkgPath, 'node_modules', pkgName)));
    }
    await Promise.all(pkgPaths.map((prefix) => installLimit(async () => {
        const s = await createStoreController_1.cached(storeControllerCache, opts);
        await supi_1.install(await readImporterManifest_1.readImporterManifestOnly(prefix, opts), Object.assign({}, await getConfigs_1.default(Object.assign({}, opts.cliArgs, { prefix }), {
            command: ['link'],
            excludeReporter: true,
        }), { localPackages, store: s.path, storeController: s.ctrl }));
    })));
    const { manifest, writeImporterManifest } = await readImporterManifest_1.default(cwd, opts);
    const newManifest = await supi_1.link(pkgPaths, path.join(cwd, 'node_modules'), Object.assign({}, linkOpts, { manifest }));
    await writeImporterManifest(newManifest);
    await Promise.all(Array.from(storeControllerCache.values())
        .map(async (storeControllerPromise) => {
        const storeControllerHolder = await storeControllerPromise;
        await storeControllerHolder.ctrl.close();
    }));
};
