"use strict";
/**
 * This is a utility file for docs library service that has functions to cater the services for
 * playbook adjacent collections.
 *
 * NOTE: 'PAC' in the filename stands for 'Playbook Adjacent Collections'
 */
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, _arguments || [])).next());
    });
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getModuleFqcnsUtils = exports.findModulesUtils = void 0;
const docsFinder_1 = require("../utils/docsFinder");
const docsParser_1 = require("../utils/docsParser");
const yaml_1 = require("../utils/yaml");
const playbookAdjacentPluginRouting = new Map();
function findModulesUtils(playbookAdjacentCollectionsPath, searchText, context, contextPath, documentUri) {
    return __awaiter(this, void 0, void 0, function* () {
        const playbookAdjacentModules = new Map();
        const playbookAdjacentModuleFqcns = new Set();
        const playbookAdjacentDocFragments = new Map();
        // find documentation for PAC
        (yield (0, docsFinder_1.findDocumentation)(playbookAdjacentCollectionsPath, "collection")).forEach((doc) => {
            playbookAdjacentModules.set(doc.fqcn, doc);
            playbookAdjacentModuleFqcns.add(doc.fqcn);
        });
        (yield (0, docsFinder_1.findDocumentation)(playbookAdjacentCollectionsPath, "collection_doc_fragment")).forEach((doc) => {
            playbookAdjacentDocFragments.set(doc.fqcn, doc);
        });
        (yield (0, docsFinder_1.findPluginRouting)(playbookAdjacentCollectionsPath, "collection")).forEach((r, collection) => playbookAdjacentPluginRouting.set(collection, r));
        // add all valid redirect routes as possible FQCNs
        for (const [collection, routesByType] of playbookAdjacentPluginRouting) {
            for (const [name, route] of routesByType.get("modules") || []) {
                if (route.redirect && !route.tombstone) {
                    playbookAdjacentModuleFqcns.add(`${collection}.${name}`);
                }
            }
        }
        // Now, start finding the module
        let hitFqcn;
        const candidateFqcns = yield getCandidateFqcns(searchText, documentUri, contextPath, context);
        // check routing
        let moduleRoute;
        for (const fqcn of candidateFqcns) {
            moduleRoute = getModuleRoute(fqcn);
            if (moduleRoute) {
                hitFqcn = fqcn;
                break; // find first
            }
        }
        // find module
        let module;
        if (moduleRoute && moduleRoute.redirect) {
            module = playbookAdjacentModules.get(moduleRoute.redirect);
        }
        else {
            for (const fqcn of candidateFqcns) {
                module = playbookAdjacentModules.get(fqcn);
                if (module) {
                    if (!hitFqcn) {
                        hitFqcn = fqcn;
                    }
                    break; // find first
                }
            }
        }
        if (module) {
            if (!module.fragments) {
                // collect information from documentation fragments
                (0, docsParser_1.processDocumentationFragments)(module, playbookAdjacentDocFragments);
            }
            if (!module.documentation) {
                // translate raw documentation into a typed structure
                module.documentation = (0, docsParser_1.processRawDocumentation)(module.rawDocumentationFragments);
            }
        }
        return [module, hitFqcn];
    });
}
exports.findModulesUtils = findModulesUtils;
function getModuleFqcnsUtils(playbookAdjacentCollectionsPath) {
    return __awaiter(this, void 0, void 0, function* () {
        const playbookAdjacentModules = new Map();
        const playbookAdjacentModuleFqcns = new Set();
        const playbookAdjacentDocFragments = new Map();
        (yield (0, docsFinder_1.findDocumentation)(playbookAdjacentCollectionsPath, "collection")).forEach((doc) => {
            playbookAdjacentModules.set(doc.fqcn, doc);
            playbookAdjacentModuleFqcns.add(doc.fqcn);
        });
        (yield (0, docsFinder_1.findDocumentation)(playbookAdjacentCollectionsPath, "collection_doc_fragment")).forEach((doc) => {
            playbookAdjacentDocFragments.set(doc.fqcn, doc);
        });
        (yield (0, docsFinder_1.findPluginRouting)(playbookAdjacentCollectionsPath, "collection")).forEach((r, collection) => playbookAdjacentPluginRouting.set(collection, r));
        // add all valid redirect routes as possible FQCNs
        for (const [collection, routesByType] of playbookAdjacentPluginRouting) {
            for (const [name, route] of routesByType.get("modules") || []) {
                if (route.redirect && !route.tombstone) {
                    playbookAdjacentModuleFqcns.add(`${collection}.${name}`);
                }
            }
        }
        return playbookAdjacentModuleFqcns;
    });
}
exports.getModuleFqcnsUtils = getModuleFqcnsUtils;
function getCandidateFqcns(searchText, documentUri, contextPath, context) {
    return __awaiter(this, void 0, void 0, function* () {
        const candidateFqcns = [];
        if (searchText.split(".").length >= 3) {
            candidateFqcns.push(searchText); // try searching as-is (FQCN match)
        }
        else {
            candidateFqcns.push(`ansible.builtin.${searchText}`); // try searching built-in
            if (documentUri) {
                const metadata = yield context.documentMetadata.get(documentUri);
                if (metadata) {
                    // try searching declared collections
                    candidateFqcns.push(...metadata.collections.map((c) => `${c}.${searchText}`));
                }
            }
            if (contextPath) {
                candidateFqcns.push(...(0, yaml_1.getDeclaredCollections)(contextPath).map((c) => `${c}.${searchText}`));
            }
        }
        return candidateFqcns;
    });
}
function getModuleRoute(fqcn) {
    var _a, _b;
    const fqcn_array = fqcn.split(".");
    if (fqcn_array.length === 3) {
        const [namespace, collection, name] = fqcn_array;
        return (_b = (_a = playbookAdjacentPluginRouting
            .get(`${namespace}.${collection}`)) === null || _a === void 0 ? void 0 : _a.get("modules")) === null || _b === void 0 ? void 0 : _b.get(name);
    }
}
//# sourceMappingURL=docsLibraryUtilsForPAC.js.map