"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
    if (mod && mod.__esModule) return mod;
    var result = {};
    if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
    __setModuleDefault(result, mod);
    return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getVarsCompletion = void 0;
const vscode_languageserver_1 = require("vscode-languageserver");
const vscode_uri_1 = require("vscode-uri");
const yaml_1 = require("yaml");
const yaml_2 = require("../utils/yaml");
const pathUri = __importStar(require("path"));
const fs_1 = require("fs");
const yaml_3 = require("yaml");
/**
 * A function that computes the possible variable auto-completions scope-wise for a given position
 * @param documentUri - uri of the document
 * @param path - array of nodes leading to that position
 * @returns a list of completion items
 */
function getVarsCompletion(documentUri, path) {
    const varsCompletion = [];
    let varPriority = 0;
    // the loop calculates and traverses till the path reaches the play level from the position where the auto-completion was asked
    while (!(0, yaml_2.isPlayParam)(path)) {
        varPriority = varPriority + 1;
        // handle case when it is a dict
        let parentKeyPath = new yaml_2.AncestryBuilder(path)
            .parent(yaml_1.YAMLMap)
            .parent(yaml_1.YAMLMap)
            .getKeyPath();
        if (parentKeyPath) {
            const parentKeyNode = parentKeyPath[parentKeyPath.length - 1];
            if ((0, yaml_1.isScalar)(parentKeyNode) &&
                typeof parentKeyNode["value"] === "string") {
                path = parentKeyPath;
                const scopedNode = path[path.length - 3].toJSON();
                if (scopedNode.hasOwnProperty("vars")) {
                    const varsObject = scopedNode["vars"];
                    if (Array.isArray(varsObject)) {
                        varsObject.forEach((element) => {
                            Object.keys(element).forEach((key) => {
                                varsCompletion.push({ variable: key, priority: varPriority });
                            });
                        });
                    }
                    else {
                        Object.keys(varsObject).forEach((key) => {
                            varsCompletion.push({ variable: key, priority: varPriority });
                        });
                    }
                }
                continue;
            }
        }
        // handle case when it is a list
        parentKeyPath = new yaml_2.AncestryBuilder(path)
            .parent(yaml_1.YAMLMap)
            .parent(yaml_1.YAMLSeq)
            .parent(yaml_1.YAMLMap)
            .getKeyPath();
        if (parentKeyPath) {
            const parentKeyNode = parentKeyPath[parentKeyPath.length - 1];
            if ((0, yaml_1.isScalar)(parentKeyNode) &&
                typeof parentKeyNode["value"] === "string") {
                path = parentKeyPath;
                const scopedNode = path[path.length - 3].toJSON();
                if (scopedNode.hasOwnProperty("vars")) {
                    const varsObject = scopedNode["vars"];
                    if (Array.isArray(varsObject)) {
                        varsObject.forEach((element) => {
                            Object.keys(element).forEach((key) => {
                                varsCompletion.push({ variable: key, priority: varPriority });
                            });
                        });
                    }
                    else {
                        Object.keys(varsObject).forEach((key) => {
                            varsCompletion.push({ variable: key, priority: varPriority });
                        });
                    }
                }
                continue;
            }
        }
    }
    // At this point path is at play level
    // At play level, there are two more ways in which vars can be defined:
    // 1. vars_prompt
    // 2. vars_files
    // handling vars_prompt
    varPriority = varPriority + 1;
    const playNode = path[path.length - 3].toJSON();
    if (playNode.hasOwnProperty("vars_prompt")) {
        const varsPromptObject = playNode["vars_prompt"];
        varsPromptObject.forEach((element) => {
            varsCompletion.push({ variable: element["name"], priority: varPriority });
        });
    }
    // handling vars_files
    varPriority = varPriority + 1;
    if (playNode.hasOwnProperty("vars_files")) {
        const varsPromptObject = playNode["vars_files"];
        const currentDirectory = pathUri.dirname(vscode_uri_1.URI.parse(documentUri).path);
        varsPromptObject.forEach((element) => {
            let varFilePath;
            if (pathUri.isAbsolute(element)) {
                varFilePath = element;
            }
            else {
                varFilePath = vscode_uri_1.URI.parse(pathUri.resolve(currentDirectory, element)).path;
            }
            // read the vars_file and get the variables declared inside it
            if ((0, fs_1.existsSync)(varFilePath)) {
                const file = (0, fs_1.readFileSync)(varFilePath, {
                    encoding: "utf8",
                });
                const contents = (0, yaml_3.parseDocument)(file).contents;
                if (contents !== null) {
                    const yamlDocContent = contents.toJSON();
                    // variables declared in the file should be in list format only
                    if (Array.isArray(yamlDocContent)) {
                        yamlDocContent.forEach((element) => {
                            if (typeof element === "object") {
                                Object.keys(element).forEach((key) => {
                                    varsCompletion.push({ variable: key, priority: varPriority });
                                });
                            }
                        });
                    }
                }
            }
        });
    }
    // return the completions as completion items
    return varsCompletion.map(({ variable, priority }) => {
        const completionItem = {
            label: variable,
            sortText: `${priority}_${variable}`,
            kind: vscode_languageserver_1.CompletionItemKind.Variable,
        };
        return completionItem;
    });
}
exports.getVarsCompletion = getVarsCompletion;
