"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getYamlValidation = exports.doValidate = void 0;
const interval_tree_1 = __importDefault(require("@flatten-js/interval-tree"));
const vscode_languageserver_1 = require("vscode-languageserver");
const yaml_1 = require("../utils/yaml");
const commandRunner_1 = require("../utils/commandRunner");
/**
 * Validates the given document.
 * @param textDocument - the document to validate
 * @param linter - uses linter
 * @param quick - only re-evaluates YAML validation and uses lint cache
 * @returns Map of diagnostics per file.
 */
async function doValidate(textDocument, validationManager, quick = true, context, connection) {
    let diagnosticsByFile = new Map();
    if (quick || !context) {
        // get validation from cache
        diagnosticsByFile =
            validationManager.getValidationFromCache(textDocument.uri) ||
                new Map();
    }
    else {
        // full validation with ansible-lint or ansible syntax-check (if ansible-lint is not installed or disabled)
        const settings = await context.documentSettings.get(textDocument.uri);
        if (!settings.validation.enabled) {
            connection?.console.log("Validation disabled");
            // this is done to remove the cache as well
            const blankDiagnostics = new Map();
            blankDiagnostics.set(textDocument.uri, []);
            validationManager.processDiagnostics(textDocument.uri, blankDiagnostics);
            validationManager.cacheDiagnostics(textDocument.uri, blankDiagnostics);
            return blankDiagnostics;
        }
        // validation using ansible-lint
        if (settings.validation.lint.enabled) {
            const commandRunner = new commandRunner_1.CommandRunner(connection, context, settings);
            const lintExecutable = settings.executionEnvironment.enabled
                ? "ansible-lint"
                : settings.validation.lint.path;
            const lintAvailability = await commandRunner.getExecutablePath(lintExecutable);
            connection?.console.log(`Path for lint: ${lintAvailability}`);
            if (lintAvailability) {
                connection?.console.log("Validating using ansible-lint");
                diagnosticsByFile = await context.ansibleLint.doValidate(textDocument);
            }
            else {
                connection?.window.showErrorMessage("Ansible-lint is not available. Kindly check the path or disable validation using ansible-lint");
            }
        }
        // validate using ansible-playbook --syntax-check
        else {
            connection?.console.log("Validating using ansible syntax-check");
            if ((0, yaml_1.isPlaybook)(textDocument)) {
                connection?.console.log("playbook file");
                diagnosticsByFile =
                    await context.ansiblePlaybook.doValidate(textDocument);
            }
            else {
                connection?.console.log("non-playbook file");
                diagnosticsByFile = new Map();
            }
        }
        if (!diagnosticsByFile.has(textDocument.uri)) {
            // In case there are no diagnostics for the file that triggered the
            // validation, set an empty array in order to clear the validation.
            diagnosticsByFile.set(textDocument.uri, []);
        }
        validationManager.cacheDiagnostics(textDocument.uri, diagnosticsByFile);
    }
    // attach quick validation for the inspected file
    for (const [fileUri, fileDiagnostics] of diagnosticsByFile) {
        if (textDocument.uri === fileUri) {
            fileDiagnostics.push(...getYamlValidation(textDocument));
        }
    }
    validationManager.processDiagnostics(textDocument.uri, diagnosticsByFile);
    return diagnosticsByFile;
}
exports.doValidate = doValidate;
function getYamlValidation(textDocument) {
    const diagnostics = [];
    const yDocuments = (0, yaml_1.parseAllDocuments)(textDocument.getText());
    const rangeTree = new interval_tree_1.default();
    yDocuments.forEach((yDoc) => {
        yDoc.errors.forEach((error) => {
            const [errStart, errEnd] = error.pos;
            if (errStart) {
                const start = textDocument.positionAt(errStart);
                const end = textDocument.positionAt(errEnd);
                const range = vscode_languageserver_1.Range.create(start, end);
                let severity;
                switch (error.name) {
                    case "YAMLParseError":
                        severity = vscode_languageserver_1.DiagnosticSeverity.Error;
                        break;
                    case "YAMLWarning":
                        severity = vscode_languageserver_1.DiagnosticSeverity.Warning;
                        break;
                    default:
                        severity = vscode_languageserver_1.DiagnosticSeverity.Information;
                        break;
                }
                let a = 0;
                let b = 0;
                if (error.linePos) {
                    a = error.linePos[0].line;
                    if (error.linePos[1]) {
                        b = error.linePos[1].line;
                    }
                }
                rangeTree.insert([a, b], {
                    message: error.message,
                    range: range || vscode_languageserver_1.Range.create(0, 0, 0, 0),
                    severity: severity,
                    source: "Ansible [YAML]",
                });
            }
        });
    });
    rangeTree.forEach((range, diag) => {
        diagnostics.push(diag);
    });
    return diagnostics;
}
exports.getYamlValidation = getYamlValidation;
