"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.mergeLoggers = exports.makeLogger = void 0;
const handler_console_1 = require("./handler-console");
const handler_file_1 = require("./handler-file");
const handler_rolling_file_1 = require("./handler-rolling-file");
const handler_debug_1 = require("./handler-debug");
const printer_1 = require("./printer");
const log_level_1 = require("./log-level");
const colorize_1 = require("./colorize");
const formatter_1 = require("./formatter");
const utils = __importStar(require("@applitools/utils"));
function makeLogger({ logger: baseLogger, ...options } = {}) {
    var _a, _b, _c, _d, _e, _f, _g;
    var _h, _j;
    if (baseLogger)
        return baseLogger.extend({ level: options.level, ...options.format });
    (_a = options.console) !== null && _a !== void 0 ? _a : (options.console = true);
    (_b = options.format) !== null && _b !== void 0 ? _b : (options.format = {});
    (_c = (_h = options.format).formatter) !== null && _c !== void 0 ? _c : (_h.formatter = formatter_1.formatter);
    (_d = (_j = options.format).colors) !== null && _d !== void 0 ? _d : (_j.colors = utils.general.getEnvValue('LOG_COLORS', 'boolean'));
    let forceInitHandler;
    if (!options.handler) {
        if (process.env.APPLITOOLS_LOG_FILE) {
            options.handler = { type: 'file', filename: process.env.APPLITOOLS_LOG_FILE };
        }
        else if (process.env.APPLITOOLS_LOG_DIR) {
            options.handler = { type: 'rolling file', dirname: process.env.APPLITOOLS_LOG_DIR };
        }
        else if (process.env.APPLITOOLS_SHOW_LOGS === 'true') {
            options.handler = { type: 'console' };
        }
        else if (process.env.DEBUG) {
            options.handler = { type: 'debug', label: options.format.label };
            options.level = log_level_1.LogLevel.all;
            options.format.label = undefined;
            options.format.timestamp = false;
            forceInitHandler = true;
        }
        else {
            options.handler = { type: 'console' };
        }
    }
    if (!utils.types.isNumber(options.level)) {
        options.level =
            (_f = (_e = options.level) !== null && _e !== void 0 ? _e : process.env.APPLITOOLS_LOG_LEVEL) !== null && _f !== void 0 ? _f : (process.env.APPLITOOLS_SHOW_LOGS === 'true' ? 'all' : 'silent');
        options.level = (_g = log_level_1.LogLevel[options.level]) !== null && _g !== void 0 ? _g : log_level_1.LogLevel.silent;
    }
    if (utils.types.has(options.handler, 'type')) {
        if (options.handler.type === 'console') {
            options.handler = (0, handler_console_1.makeConsoleHandler)();
        }
        else if (options.handler.type === 'debug') {
            options.handler = (0, handler_debug_1.makeDebugHandler)({ label: options.format.label, ...options.handler });
        }
        else if (options.handler.type === 'file') {
            options.handler = (0, handler_file_1.makeFileHandler)(options.handler);
            options.format.colors = false;
        }
        else if (options.handler.type === 'rolling file') {
            options.handler = (0, handler_rolling_file_1.makeRollingFileHandler)(options.handler);
            options.format.colors = false;
        }
    }
    else if (!utils.types.isFunction(options.handler, 'log')) {
        throw new Error('Handler have to implement `log` method or use one of the built-in handler names under `type` prop');
    }
    options.console = options.console
        ? utils.types.isObject(options.console)
            ? options.console
            : (0, handler_console_1.makeConsoleHandler)()
        : options.handler;
    const logger = {
        isLogger: true,
        options,
        console: (0, printer_1.makePrinter)({ handler: options.console, level: log_level_1.LogLevel.all, format: { ...options.format, prelude: false } }),
        ...(0, printer_1.makePrinter)({ handler: options.handler, level: options.level, format: options.format }),
        extend(optionsOrLogger, extraOptions) {
            const extendOptions = [options];
            if (utils.types.has(optionsOrLogger, 'isLogger')) {
                if (optionsOrLogger !== logger)
                    extendOptions.push(optionsOrLogger.options);
                if (extraOptions)
                    extendOptions.push({ console: extraOptions.console, level: extraOptions.level, format: extraOptions });
            }
            else if (optionsOrLogger) {
                extendOptions.push({ console: optionsOrLogger.console, level: optionsOrLogger.level, format: optionsOrLogger });
            }
            const extendedOptions = mergeOptions(...extendOptions);
            if (forceInitHandler && extendedOptions.handler === options.handler) {
                extendedOptions.handler = undefined;
            }
            return makeLogger(extendedOptions);
        },
        colorize: colorize_1.colorize,
        open() {
            var _a, _b;
            if (!options.extended)
                (_b = (_a = options.handler).open) === null || _b === void 0 ? void 0 : _b.call(_a);
        },
        close() {
            var _a, _b;
            if (!options.extended)
                (_b = (_a = options.handler).close) === null || _b === void 0 ? void 0 : _b.call(_a);
        },
    };
    return logger;
}
exports.makeLogger = makeLogger;
function mergeLoggers(...loggers) {
    if (loggers.length === 1)
        return loggers[0];
    const mergedOptions = mergeOptions(...loggers.map(logger => {
        var _a;
        return {
            ...logger.options,
            format: {
                ...logger.options.format,
                tags: ((_a = logger.options.format) === null || _a === void 0 ? void 0 : _a.tags) &&
                    (utils.types.isArray(logger.options.format.tags[0])
                        ? logger.options.format.tags
                        : [logger.options.format.tags]),
            },
        };
    }));
    return makeLogger(mergedOptions);
}
exports.mergeLoggers = mergeLoggers;
function mergeOptions(...options) {
    return options.reduce((baseOptions, currentOptions) => {
        var _a, _b, _c, _d;
        return {
            ...baseOptions,
            ...currentOptions,
            format: {
                ...baseOptions.format,
                ...currentOptions.format,
                tags: mergeTags((_b = (_a = baseOptions.format) === null || _a === void 0 ? void 0 : _a.tags) !== null && _b !== void 0 ? _b : [], (_d = (_c = currentOptions.format) === null || _c === void 0 ? void 0 : _c.tags) !== null && _d !== void 0 ? _d : []),
            },
        };
    }, {});
}
function mergeTags(...tags) {
    return tags.reduce((baseTags, currentTags) => {
        if (utils.types.isArray(baseTags[0])) {
            let mergedTags = baseTags.map(baseTags => [...baseTags]);
            if (utils.types.isArray(currentTags[0])) {
                mergedTags.push(...currentTags.map(currentTags => [...currentTags]));
            }
            else {
                mergedTags = mergedTags.map(mergedTags => [
                    ...new Set([...mergedTags, ...currentTags]),
                ]);
            }
            return mergedTags;
        }
        else {
            return utils.types.isArray(currentTags[0])
                ? [...baseTags, ...currentTags]
                : [...new Set([...baseTags, ...currentTags])];
        }
    }, []);
}
