"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseConfig = void 0;
const lodash_1 = __importDefault(require("lodash"));
const gemini_configparser_1 = require("gemini-configparser");
const chalk_1 = __importDefault(require("chalk"));
const common_utils_1 = require("../common-utils");
const constants_1 = require("../constants");
const custom_gui_asserts_1 = require("./custom-gui-asserts");
const ENV_PREFIX = 'html_reporter_';
const CLI_PREFIX = '--html-reporter-';
const ALLOWED_PLUGIN_DESCRIPTION_FIELDS = new Set(['name', 'component', 'point', 'position', 'config']);
const assertType = (name, validationFn, type) => {
    return (v) => {
        if (!validationFn(v)) {
            throw new Error(`"${name}" option must be ${type}, but got ${typeof v}`);
        }
    };
};
const assertString = (name) => assertType(name, lodash_1.default.isString, 'string');
const assertBoolean = (name) => assertType(name, lodash_1.default.isBoolean, 'boolean');
const assertNumber = (name) => assertType(name, lodash_1.default.isNumber, 'number');
const assertSaveFormat = (saveFormat) => {
    const formats = Object.values(constants_1.SaveFormat);
    if (!lodash_1.default.isString(saveFormat)) {
        throw new Error(`"saveFormat" option must be string, but got ${typeof saveFormat}`);
    }
    if (!formats.includes(saveFormat)) {
        throw new Error(`"saveFormat" must be "${formats.join('", "')}", but got "${saveFormat}"`);
    }
};
const assertErrorPatterns = (errorPatterns) => {
    if (!lodash_1.default.isArray(errorPatterns)) {
        throw new Error(`"errorPatterns" option must be array, but got ${typeof errorPatterns}`);
    }
    for (const patternInfo of errorPatterns) {
        if (!lodash_1.default.isString(patternInfo) && !lodash_1.default.isPlainObject(patternInfo)) {
            throw new Error(`Element of "errorPatterns" option must be plain object or string, but got ${typeof patternInfo}`);
        }
        if (lodash_1.default.isPlainObject(patternInfo)) {
            for (const field of ['name', 'pattern']) {
                if (!lodash_1.default.isString(patternInfo[field])) {
                    throw new Error(`Field "${field}" in element of "errorPatterns" option must be string, but got ${typeof patternInfo[field]}`);
                }
            }
        }
    }
};
const assertMetaInfoBaseUrls = (metaInfoBaseUrls) => {
    if (!lodash_1.default.isObject(metaInfoBaseUrls)) {
        throw new Error(`"metaInfoBaseUrls" option must be object, but got ${typeof metaInfoBaseUrls}`);
    }
    for (const keyStr in metaInfoBaseUrls) {
        const key = keyStr;
        if (!lodash_1.default.isString(metaInfoBaseUrls[key])) {
            throw new Error(`Value of "${key}" in "metaInfoBaseUrls" option must be string, but got ${typeof metaInfoBaseUrls[key]}`);
        }
    }
};
const assertArrayOf = (itemsType, name, predicateFn) => {
    return (value) => {
        if (!lodash_1.default.isArray(value)) {
            throw new Error(`"${name}" option must be an array, but got ${typeof value}`);
        }
        for (const item of value) {
            if (!predicateFn(item)) {
                throw new Error(`"${name}" option must be an array of ${itemsType} but got ${typeof item} for one of items`);
            }
        }
    };
};
const assertPluginDescription = (description) => {
    const maybeDescription = description;
    if (!lodash_1.default.isPlainObject(maybeDescription)) {
        throw new Error(`plugin description expected to be an object but got ${typeof description}`);
    }
    for (const field of ['name', 'component']) {
        if (!maybeDescription[field] || !lodash_1.default.isString(maybeDescription[field])) {
            throw new Error(`"plugins.${field}" option must be non-empty string but got ${typeof maybeDescription[field]}`);
        }
    }
    if (maybeDescription.point && !lodash_1.default.isString(maybeDescription.point)) {
        throw new Error(`"plugins.point" option must be string but got ${typeof maybeDescription.point}`);
    }
    if (maybeDescription.position && !['after', 'before', 'wrap'].includes(maybeDescription.position)) {
        throw new Error(`"plugins.position" option got an unexpected value "${maybeDescription.position}"`);
    }
    if (maybeDescription.config && !lodash_1.default.isPlainObject(maybeDescription.config)) {
        throw new Error(`plugin configuration expected to be an object but got ${typeof maybeDescription.config}`);
    }
    lodash_1.default.forOwn(description, (value, key) => {
        if (!ALLOWED_PLUGIN_DESCRIPTION_FIELDS.has(key)) {
            throw new Error(`a "plugins" item has unexpected field "${key}" of type ${typeof value}`);
        }
    });
    return true;
};
const assertDiffMode = (diffMode) => {
    if (!lodash_1.default.isString(diffMode)) {
        throw new Error(`"diffMode" option must be a string, but got ${typeof diffMode}`);
    }
    const availableValues = Object.values(constants_1.DiffModes).map(v => v.id);
    if (!availableValues.includes(diffMode)) {
        throw new Error(`"diffMode" must be one of "${availableValues.join('", "')}", but got "${diffMode}"`);
    }
};
const mapErrorPatterns = (errorPatterns) => {
    return errorPatterns.map(patternInfo => {
        return lodash_1.default.isString(patternInfo)
            ? { name: patternInfo, pattern: patternInfo }
            : patternInfo;
    });
};
const deprecationWarning = (name) => {
    common_utils_1.logger.warn(chalk_1.default.red(`Warning: field "${name}" is deprecated and will be removed soon from html-reporter config.`));
};
const getParser = () => {
    return (0, gemini_configparser_1.root)((0, gemini_configparser_1.section)({
        enabled: (0, gemini_configparser_1.option)({
            defaultValue: true,
            parseEnv: JSON.parse,
            parseCli: JSON.parse,
            validate: assertBoolean('enabled')
        }),
        path: (0, gemini_configparser_1.option)({
            defaultValue: 'html-report',
            validate: assertString('path')
        }),
        saveFormat: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.SaveFormat.SQLITE,
            validate: assertSaveFormat
        }),
        saveErrorDetails: (0, gemini_configparser_1.option)({
            defaultValue: false,
            parseEnv: JSON.parse,
            parseCli: JSON.parse,
            validate: assertBoolean('saveErrorDetails')
        }),
        commandsWithShortHistory: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.commandsWithShortHistory,
            validate: assertArrayOf('strings', 'commandsWithShortHistory', lodash_1.default.isString)
        }),
        defaultView: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.defaultView,
            validate: assertString('defaultView')
        }),
        diffMode: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.diffMode,
            validate: assertDiffMode
        }),
        baseHost: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.baseHost,
            validate: assertString('baseHost')
        }),
        lazyLoadOffset: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.lazyLoadOffset,
            validate: (value) => lodash_1.default.isNull(value) || deprecationWarning('lazyLoadOffset')
        }),
        errorPatterns: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.errorPatterns,
            parseEnv: JSON.parse,
            validate: assertErrorPatterns,
            map: mapErrorPatterns
        }),
        metaInfoBaseUrls: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.metaInfoBaseUrls,
            parseEnv: JSON.parse,
            parseCli: JSON.parse,
            validate: assertMetaInfoBaseUrls
        }),
        customGui: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.customGui,
            validate: custom_gui_asserts_1.assertCustomGui
        }),
        customScripts: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.customScripts,
            validate: assertArrayOf('functions', 'customScripts', lodash_1.default.isFunction)
        }),
        yandexMetrika: (0, gemini_configparser_1.section)({
            counterNumber: (0, gemini_configparser_1.option)({
                defaultValue: constants_1.configDefaults.yandexMetrika.counterNumber,
                parseEnv: Number,
                parseCli: Number,
                validate: (value) => lodash_1.default.isNull(value) || assertNumber('yandexMetrika.counterNumber')(value)
            })
        }),
        pluginsEnabled: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.pluginsEnabled,
            parseEnv: JSON.parse,
            parseCli: JSON.parse,
            validate: assertBoolean('pluginsEnabled')
        }),
        plugins: (0, gemini_configparser_1.option)({
            defaultValue: constants_1.configDefaults.plugins,
            parseEnv: JSON.parse,
            parseCli: JSON.parse,
            validate: assertArrayOf('plugin descriptions', 'plugins', assertPluginDescription)
        })
    }), { envPrefix: ENV_PREFIX, cliPrefix: CLI_PREFIX });
};
const parseConfig = (options) => {
    const env = process.env;
    const argv = process.argv;
    // TODO: add support for different types of input and output in gemini-configparser
    return getParser()({ options: options, env, argv });
};
exports.parseConfig = parseConfig;
//# sourceMappingURL=index.js.map