"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.makeSettingsUnique = exports.structureSettings = exports.toDotNotation = void 0;
const Handlebars = __importStar(require("handlebars"));
const fs = __importStar(require("fs"));
const settingsManager_1 = require("../src/services/settingsManager");
const path = __importStar(require("path"));
const _ = __importStar(require("lodash"));
// Get the default settings values from settingsManager class
const settingsManager = new settingsManager_1.SettingsManager(null, false);
const defaultSettings = {
    ansible: settingsManager.defaultSettingsWithDescription,
};
// Convert the nested settings value to single-level object with keys in the form of dotted notations (intermediate step)
const settingsInDotNotation = toDotNotation(defaultSettings);
// Convert the dotted settings value to single-level object with the keys as { settings, defaultValue, description }  (final step)
const arrayOfDefaultSettings = structureSettings(settingsInDotNotation);
// Use handlebars.js to generate doc file with `defaultSettings.handlebars` as template
// ## [`ansible.ansible.path`](#xxx) {: #xxx }
const TEMPLATE = `
# Language Server Settings

The following are the default values of the settings provided by the Ansible Language Server:

{{#each arrayOfDefaultSettings}}
## [\`{{ setting }}\`](#{{ slug }}) { #{{ slug }} data-toc-label={{ slug }} }
{{#if description}}
{{description}}
{{/if}}
{{#ifValueArray valueType}}
{{#each this.defaultValue}}
  - **{{key}}**: {{description}}. Default value:
{{#if defaultValue}}
\`{{defaultValue}}\`
{{else}}
{{#ifEqualsFalse defaultValue}}
\`false\`
{{else}}
\`""\`
{{/ifEqualsFalse}}
{{/if}}
{{/each}}
{{else}}
. Default value:
{{#if defaultValue}}
\`\`{{defaultValue}}\`\`
{{else}}
{{#ifEqualsFalse defaultValue}}
\`\`false\`\`
{{else}}
\`\`""\`\`
{{/ifEqualsFalse}}
{{/if}}
{{/ifValueArray}}

{{/each}}
`;
const WARNING_IN_README = "<!-- {{! Do not edit this file directly. This is generated by the `generate-settings-readme` npm script }} -->";
const settingsReadmeFileUri = path.join(__dirname, "..", "..", "..", "docs", "als", "settings.md");
// Register a special function for handlebars to deal with comparison of stringed value of false
// Else, normal #if treats it as boolean, even after converting booleans to strings in typescript
Handlebars.registerHelper("ifEqualsFalse", function (arg1, options) {
    return String(arg1) === "false" ? options.fn(this) : options.inverse(this);
});
// Register a special function for handlebars to deal with the checking of "list" as value type of settings
Handlebars.registerHelper("ifValueArray", function (arg1, options) {
    return arg1.toString() === "list"
        ? options.fn(this)
        : options.inverse(this);
});
const template = Handlebars.compile(TEMPLATE);
const output = template({ arrayOfDefaultSettings });
fs.writeFileSync(settingsReadmeFileUri, `${WARNING_IN_README}\n${output}`);
console.log(`Readme file for settings description and default value generated.`);
console.log(`File: ${settingsReadmeFileUri}`);
function toDotNotation(obj, res = {}, current = "") {
    for (const key in obj) {
        const value = obj[key];
        const newKey = current ? `${current}.${key}` : key; // joined key with dot
        if (value && typeof value === "object") {
            if (_.isArray(value) && value[0]) {
                toDotNotation(value[0], res, `${newKey}._array`); // it's an array object, so do it again (to identify array '._array' is added)
            }
            else {
                toDotNotation(value, res, newKey); // it's a nested object, so do it again
            }
        }
        else {
            res[newKey] = value; // it's not an object, so set the property
        }
    }
    return res;
}
exports.toDotNotation = toDotNotation;
function structureSettings(settingsInDotNotation) {
    // Form an appropriate structure so that it is easier to iterate over it in the template
    // Structure is as follows:
    //
    // arrayOfDefaultSettings: [
    //   {
    //     key: ansible.first.setting,
    //     defaultValue: some-values,
    //     description: 'description for setting 1',
    //     valueType: 'value-type-of-setting-1'
    //   },
    //   {
    //     key: ansible.second.setting,
    //     defaultValue: another-values,
    //     description: 'description for setting 2',
    //     valueType: 'value-type-of-setting-2'
    //   }
    //   {
    //     key: ansible.third.setting,
    //     defaultValue: [
    //       first-sub-value: {
    //       defaultValue: default-sub-value-1
    //       description: 'description for sub value 1'
    //       }
    //       second-sub-value: {
    //       defaultValue: default-sub-value-2
    //       description: 'description for sub value 2'
    //       }
    //     ],
    //     valueType: 'list'
    //   }
    // ]
    const settingsArray = [];
    const objWithArrayValues = [];
    const keysWithArrayValues = []; // keep track of keys whose elements are array
    for (const k in settingsInDotNotation) {
        const keyArray = k.split(".");
        keyArray.splice(-1, 1);
        const key = keyArray.join(".");
        // Find keys that have array elements
        const arrayElementIndex = keyArray.findIndex((e) => e === "_array");
        const arrayElement = arrayElementIndex >= 0 ? keyArray[arrayElementIndex - 1] : undefined;
        // if found, make a combined obj of such elements and group them later
        if (arrayElement) {
            keysWithArrayValues.push(keyArray.slice(0, arrayElementIndex).join("."));
            const arrayObj = {
                parent: keyArray.slice(0, arrayElementIndex).join("."),
                key: keyArray[arrayElementIndex + 1],
                defaultValue: settingsInDotNotation[`${key}.default`].toString() // convert to string for showing the actual value in doc
                    ? settingsInDotNotation[`${key}.default`]
                    : "",
                description: settingsInDotNotation[`${key}.description`],
            };
            objWithArrayValues.push(arrayObj);
            // break;
        }
        else {
            const obj = {
                setting: key,
                defaultValue: settingsInDotNotation[`${key}.default`].toString() // convert to string for showing the actual value in doc
                    ? settingsInDotNotation[`${key}.default`]
                    : "",
                description: settingsInDotNotation[`${key}.description`],
                valueType: typeof settingsInDotNotation[`${key}.default`],
                slug: key.replace("ansible.", ""),
            };
            settingsArray.push(obj);
        }
    }
    // group the array elements based on their parent key
    const arrayObjFinal = _.groupBy(makeSettingsUnique(objWithArrayValues), (obj) => obj.parent);
    // add them back to the settingsArray with appropriate structure and value
    for (const k in arrayObjFinal) {
        const obj = {
            setting: k,
            defaultValue: arrayObjFinal[k],
            valueType: "list",
            slug: k.replace("ansible.", ""),
        };
        settingsArray.push(obj);
    }
    return makeSettingsUnique(settingsArray);
}
exports.structureSettings = structureSettings;
function makeSettingsUnique(arrayObject) {
    const uniqueSettings = arrayObject.filter((value, index) => {
        const _value = JSON.stringify(value);
        return (index ===
            arrayObject.findIndex((obj) => {
                return JSON.stringify(obj) === _value;
            }));
    });
    return uniqueSettings;
}
exports.makeSettingsUnique = makeSettingsUnique;
