"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.newLogger = exports.NewMainLogger = exports.main = void 0;
const tsLogger = __importStar(require("tslog"));
const util_1 = require("util");
const types_1 = require("./types");
const uuid_1 = require("uuid");
// class to wrap all non-native errors in a safe error
class ErrorWrapper extends Error {
    constructor(err) {
        super();
        this.message = err.message;
        this.name = err.name;
        this.stack = err.stack;
    }
}
const NewMainLogger = (settings) => {
    exports.main = (0, exports.newLogger)(settings);
};
exports.NewMainLogger = NewMainLogger;
const loggerSettingsToTslogSettings = (settings) => {
    return settings;
};
const loggerSettingsToTslogObj = (settings) => {
    const obj = {};
    if (settings === null || settings === void 0 ? void 0 : settings.tracingId) {
        obj[types_1.TRACING_KEY] = settings === null || settings === void 0 ? void 0 : settings.tracingId;
    }
    if (settings === null || settings === void 0 ? void 0 : settings.subject) {
        obj[types_1.SUBJECT_KEY] = settings === null || settings === void 0 ? void 0 : settings.subject;
    }
    if (settings === null || settings === void 0 ? void 0 : settings.service) {
        obj[types_1.SERVICE_KEY] = settings === null || settings === void 0 ? void 0 : settings.service;
    }
    return Object.assign(Object.assign({}, obj), getGroupId());
};
const getLoggerLevel = (settings) => {
    switch (settings === null || settings === void 0 ? void 0 : settings.level) {
        case "DEBUG":
            return types_1.Level.Debug;
        case "WARN":
            return types_1.Level.Warn;
        case "ERROR":
            return types_1.Level.Error;
    }
    return types_1.Level.Info;
};
const getGroupId = () => {
    return { [types_1.LOGGER_GROUP_KEY]: (0, uuid_1.v4)() };
};
const newLogger = (settings) => {
    const s = loggerSettingsToTslogSettings(settings);
    const obj = loggerSettingsToTslogObj(settings);
    return new Logger(getLoggerLevel(settings), s, obj);
};
exports.newLogger = newLogger;
class Logger extends tsLogger.Logger {
    constructor(level, settings, logObj) {
        const expandedSettings = Object.assign(Object.assign({}, settings), { hideLogPositionForProduction: true });
        expandedSettings.type = "json";
        expandedSettings.minLevel = level;
        expandedSettings.overwrite = {
            addMeta: (logObj, logLevelId, logLevelName) => {
                return Object.assign(Object.assign({}, logObj), this.getMeta(logLevelId, logLevelName, this.settings.name, this.settings.parentNames));
            },
            toLogObj: (args, clonesLogObj) => {
                let logObj = {};
                const thisLogObj = this.obj;
                for (const key of Object.keys(thisLogObj)) {
                    if (this.isError(thisLogObj[key])) {
                        logObj[key] = this.toErrorObject(thisLogObj[key]);
                    }
                    else {
                        logObj[key] = thisLogObj[key];
                    }
                }
                for (let i = 0; i < args.length; i++) {
                    // after 3rd param we just add index-2
                    if (i > 2) {
                        logObj[(i - 2).toString()] = args[i];
                    }
                    // error, message, fields
                    // error, message
                    // message, fields
                    // message
                    if (this.isError(args[i])) {
                        logObj["error"] = this.toErrorObject(args[i]);
                    }
                    else if (args[i] instanceof String || typeof args[i] === "string") {
                        logObj["message"] = args[i];
                    }
                    else if (args[i] instanceof Object) {
                        logObj = Object.assign(Object.assign({}, logObj), args[i]);
                    }
                    else {
                        logObj["message"] = args[i];
                    }
                }
                // convert the log attributes to a T and return it
                return logObj;
            },
        };
        super(expandedSettings, logObj);
        this.obj = logObj || {};
    }
    getChildLogger(name) {
        // we concat logger names directly here
        // another options is to inject [this.settings.parentNames, this.settings.name] in settings
        // to preserve tslog behavior
        let n = `${this.settings.name}`;
        if (name === null || name === void 0 ? void 0 : name.length) {
            n = `${this.settings.name}.${name}`;
        }
        return new Logger(this.settings.minLevel, Object.assign(Object.assign(Object.assign({}, this.settings), { name: n }), getGroupId()));
    }
    withError(err) {
        if (!this.isError(err)) {
            return this;
        }
        const _err = this.wrapError(err);
        return new Logger(this.settings.minLevel, this.settings, Object.assign(Object.assign({}, this.obj), { error: _err }));
    }
    with(args) {
        return new Logger(this.settings.minLevel, this.settings, Object.assign(Object.assign({}, this.obj), args));
    }
    toErrorObject(error) {
        var _a;
        return {
            nativeError: error,
            name: (_a = error.name) !== null && _a !== void 0 ? _a : "Error",
            message: error.message,
            [types_1.STACKTRACE_KEY]: error.stack,
        };
    }
    isError(e) {
        // An error could be an instance of Error while not being a native error
        // or could be from a different realm and not be instance of Error but still
        // be a native error.
        if ((util_1.types === null || util_1.types === void 0 ? void 0 : util_1.types.isNativeError) != null && util_1.types.isNativeError(e)) {
            return true;
        }
        return e instanceof Error;
    }
    wrapError(e) {
        if ((util_1.types === null || util_1.types === void 0 ? void 0 : util_1.types.isNativeError) != null && util_1.types.isNativeError(e)) {
            return e;
        }
        return new ErrorWrapper(e);
    }
    getMeta(logLevelId, logLevelName, name, parentNames) {
        var _a;
        // faster than spread operator
        return Object.assign({}, {
            runtime: ![typeof window, typeof document].includes("undefined") ? "Browser" : "Generic",
            browser: (_a = globalThis === null || globalThis === void 0 ? void 0 : globalThis["navigator"]) === null || _a === void 0 ? void 0 : _a.userAgent,
        }, {
            name,
            parentNames,
            date: new Date(),
            logLevelId,
            logLevelName,
        });
    }
}
exports.default = Logger;
//# sourceMappingURL=logger.js.map