"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const error_1 = require("@pnpm/error");
const logger_1 = require("@pnpm/logger");
const store_path_1 = require("@pnpm/store-path");
const archy = require("archy");
const supi_1 = require("supi");
const createStoreController_1 = require("../createStoreController");
const help_1 = require("./help");
class StoreStatusError extends error_1.default {
    constructor(modified) {
        super('MODIFIED_DEPENDENCY', '');
        this.modified = modified;
    }
}
async function default_1(input, opts) {
    let store;
    switch (input[0]) {
        case 'status':
            return statusCmd(opts);
        case 'prune':
            store = await createStoreController_1.default(opts);
            const storePruneOptions = Object.assign(opts, {
                store: store.path,
                storeController: store.ctrl,
            });
            return supi_1.storePrune(storePruneOptions);
        case 'add':
            store = await createStoreController_1.default(opts);
            return supi_1.storeAdd(input.slice(1), {
                prefix: opts.prefix,
                registries: opts.registries,
                reporter: opts.reporter,
                storeController: store.ctrl,
                tag: opts.tag,
            });
        case 'usages':
            store = await createStoreController_1.default(opts);
            const packageSelectors = input.slice(1);
            const packageUsagesBySelectors = await supi_1.storeUsages(packageSelectors, {
                reporter: opts.reporter,
                storeController: store.ctrl,
            });
            prettyPrintUsages(packageSelectors, packageUsagesBySelectors);
            return;
        default:
            help_1.default(['store']);
            if (input[0]) {
                throw new error_1.default('INVALID_STORE_COMMAND', `"store ${input[0]}" is not a pnpm command. See "pnpm help store".`);
            }
    }
}
exports.default = default_1;
async function statusCmd(opts) {
    const modifiedPkgs = await supi_1.storeStatus(Object.assign(opts, {
        store: await store_path_1.default(opts.prefix, opts.store),
    }));
    if (!modifiedPkgs || !modifiedPkgs.length) {
        logger_1.default.info({
            message: 'Packages in the store are untouched',
            prefix: opts.prefix,
        });
        return;
    }
    throw new StoreStatusError(modifiedPkgs);
}
/**
 * Uses archy to output package usages in a directory-tree like format.
 * @param packageUsages a list of PackageUsage, one per query
 */
function prettyPrintUsages(selectors, packageUsagesBySelectors) {
    // Create nodes for top level usage response
    const packageUsageNodes = selectors.map((selector) => {
        // Create label for root node
        const label = `Package: ${selector}`;
        if (!packageUsagesBySelectors[selector].length) {
            // If not found in store, just output string
            return {
                label,
                nodes: [
                    'Not found in store'
                ]
            };
        }
        // This package was found in the store, create children for all package ids
        const foundPackagesNodes = packageUsagesBySelectors[selector].map((foundPackage) => {
            const label = `Package in store: ${foundPackage.packageId}`;
            // Now create children for all locations this package id is used
            const locations = foundPackage.usages;
            const locationNodes = locations.map(location => {
                return {
                    label: 'Project with dependency: ' + location
                };
            });
            // Now create node for the package found in the store
            return {
                label,
                nodes: locationNodes.length === 0 ? ['No pnpm projects using this package'] : locationNodes
            };
        });
        // Now create node for the original query
        return {
            label,
            nodes: foundPackagesNodes
        };
    });
    const rootTrees = packageUsageNodes.map(node => archy(node));
    rootTrees.forEach(tree => logger_1.globalInfo(tree));
}
