"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.AnsibleInventory = void 0;
const commandRunner_1 = require("../utils/commandRunner");
const vscode_uri_1 = require("vscode-uri");
/* Example of minimal inventory object, anything else may be missing.


{
    "_meta": {
        "hostvars": {}
    },
    "all": {
        "children": [
            "ungrouped"
        ]
    }
}

Example of more complex inventory.
{
    "_meta": {
        "hostvars": {
            "foo.example.com": {
                "var_bool": true,
                "var_number": 1,
                "var_str": "bar"
            }
        }
    },
    "all": {
        "children": [
            "ungrouped",
            "webservers",
            "others"
        ]
    },
    "ungrouped": {
        "hosts": [
            "zoo"
        ]
    },
    "webservers": {
        "children": [
            "webservers-east",
            "webservers-west"
        ],
        "hosts": [
            "foo.example.com",
            "www01.example.com",
            "www02.example.com",
            "www03.example.com",
        ]
    }
}
*/
/**
 * Class to extend ansible-inventory executable as a service
 */
class AnsibleInventory {
    connection;
    context;
    _hostList = [];
    constructor(connection, context) {
        this.connection = connection;
        this.context = context;
    }
    async initialize() {
        const settings = await this.context.documentSettings.get(this.context.workspaceFolder.uri);
        const commandRunner = new commandRunner_1.CommandRunner(this.connection, this.context, settings);
        const defaultHostListPath = new Set((await this.context.ansibleConfig).default_host_list);
        const workingDirectory = vscode_uri_1.URI.parse(this.context.workspaceFolder.uri).path;
        // Get inventory hosts
        const ansibleInventoryResult = await commandRunner.runCommand("ansible-inventory", "--list", workingDirectory, defaultHostListPath);
        let inventoryHostsObject = {};
        try {
            inventoryHostsObject = JSON.parse(ansibleInventoryResult.stdout);
        }
        catch (error) {
            this.connection.console.error(`Exception in AnsibleInventory service: ${JSON.stringify(error)}`);
        }
        this._hostList = parseInventoryHosts(inventoryHostsObject);
    }
    get hostList() {
        return this._hostList;
    }
}
exports.AnsibleInventory = AnsibleInventory;
/**
 * A utility function to parse the hosts object from ansible-inventory executable
 * to a more usable structure that can be used during auto-completions
 * @param hostObj - nested object of hosts
 * @returns an array of object with host and priority as keys
 */
function parseInventoryHosts(hostObj) {
    if (!("all" in hostObj &&
        typeof hostObj.all === "object" &&
        "children" in hostObj.all &&
        Array.isArray(hostObj.all.children))) {
        return [];
    }
    const topLevelGroups = hostObj.all.children.filter((item) => item !== "ungrouped");
    const groupsHavingChildren = topLevelGroups.filter((item) => hostObj[`${item}`] && hostObj[`${item}`].children);
    const otherGroups = getChildGroups(groupsHavingChildren, hostObj);
    // Set priorities: top level groups (1), other groups (2), ungrouped (3), hosts for groups (4), localhost (5)
    const topLevelGroupsObjList = topLevelGroups.map((item) => {
        return { host: item, priority: 1 };
    });
    const otherGroupsObjList = otherGroups.map((item) => {
        return { host: item, priority: 2 };
    });
    const allGroups = [
        ...topLevelGroupsObjList,
        ...otherGroupsObjList,
    ];
    let ungroupedHostsObjList = [];
    if ("ungrouped" in hostObj &&
        typeof hostObj.ungrouped === "object" &&
        "hosts" in hostObj.ungrouped &&
        Array.isArray(hostObj.ungrouped.hosts) &&
        hostObj.ungrouped) {
        ungroupedHostsObjList = hostObj.ungrouped.hosts.map((item) => {
            return { host: item, priority: 3 };
        });
    }
    // Add 'localhost' and 'all' to the inventory list
    const localhostObj = { host: "localhost", priority: 5 };
    const allHostObj = { host: "all", priority: 6 };
    let allHosts = [localhostObj, allHostObj, ...ungroupedHostsObjList];
    for (const group of allGroups) {
        if (hostObj[`${group.host}`] && hostObj[`${group.host}`].hosts) {
            const hostsObj = hostObj[`${group.host}`].hosts.map((item) => {
                return { host: item, priority: 4 };
            });
            allHosts = [...allHosts, ...hostsObj];
        }
    }
    return [...allGroups, ...allHosts];
}
function getChildGroups(groupList, hostObj, res = []) {
    for (const host of groupList) {
        if (hostObj[`${host}`].children) {
            getChildGroups(hostObj[`${host}`].children, hostObj, res);
        }
        else {
            res.push(host);
        }
    }
    return res;
}
