"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildLogger = exports.enableProdMode = exports.getLoggerTransports = exports.getLoggerFormat = exports.LoggerConfigSchema = void 0;
const winston_1 = require("winston");
const winston_daily_rotate_file_1 = __importDefault(require("winston-daily-rotate-file"));
const fecha_1 = require("fecha");
const fs_1 = require("@f2/fs");
const config_1 = require("@f2/config");
const joi_1 = __importDefault(require("@f2/joi"));
const root_logger_1 = require("./root-logger");
const path_1 = require("path");
const purge_builder_1 = require("./purge/purge.builder");
exports.LoggerConfigSchema = joi_1.default.object({
    console: joi_1.default.boolean().default(false),
    level: joi_1.default.string().allow('debug', 'info', 'error').default('debug'),
    dateFormat: joi_1.default.string().default('YYYY-MM-DD'),
    timeFormat: joi_1.default.string().default('HH:mm:ss.SSS'),
    path: joi_1.default.string().default('log'),
    rotate: joi_1.default.string().allow('daily', 'size').default('daily'),
    maxfiles: joi_1.default.number(),
    maxsize: joi_1.default.number(),
    transports: joi_1.default.array().items(joi_1.default.object()).default([]),
    serializeError: joi_1.default.function(),
    purge: purge_builder_1.LoggerPurgerSchema
});
function getLoggerFormat(config, scopeBag, colorize) {
    const formats = [
        winston_1.format.timestamp(),
        (0, winston_1.format)((info) => {
            const at = new Date(info.timestamp);
            info.timestamp = (0, fecha_1.format)(at, config.dateFormat + ' ' + config.timeFormat);
            return info;
        })(),
        winston_1.format.ms(),
        winston_1.format.label({
            label: 'main'
        }),
        winston_1.format.align()
    ];
    if (colorize) {
        formats.push(winston_1.format.colorize());
    }
    formats.push(winston_1.format.printf((info) => {
        const timestamp = info.timestamp;
        let scope = info.scope;
        if (scope) {
            const escape = ''.padEnd(scopeBag.maxLength - scope.length, ' ');
            scope = '[' + scope + ']';
            if (colorize) {
                const colorizer = winston_1.format.colorize();
                scope = colorizer.colorize('scope', scope);
            }
            return `${timestamp} ${scope} ${escape} ${info.level}: ${info.message}`;
        }
        return `${timestamp} ${info.level}: ${info.message}`;
    }));
    return winston_1.format.combine(...formats);
}
exports.getLoggerFormat = getLoggerFormat;
function getLoggerTransports(config, scopeBag) {
    const transports = config.transports;
    const commonFormat = getLoggerFormat(config, scopeBag, false);
    if (config.rotate === 'daily') {
        transports.push(...[
            new winston_daily_rotate_file_1.default({
                filename: (0, path_1.join)(config.path, '%DATE%.log'),
                datePattern: config.dateFormat,
                format: commonFormat,
                json: false
            }),
            new winston_daily_rotate_file_1.default({
                filename: (0, path_1.join)(config.path, '%DATE%.error.log'),
                datePattern: config.dateFormat,
                format: commonFormat,
                json: false,
                level: 'error'
            })
        ]);
    }
    else {
        const maxsize = config.maxsize || 500000;
        const maxfiles = config.maxfiles || 5;
        transports.push(...[
            new winston_1.transports.File({
                filename: (0, path_1.join)(config.path, 'log'),
                maxsize: maxsize,
                maxFiles: maxfiles,
                format: commonFormat,
                tailable: true
            }),
            new winston_1.transports.File({
                filename: (0, path_1.join)(config.path, 'error.log'),
                level: 'error',
                maxsize: maxsize,
                maxFiles: maxfiles,
                format: commonFormat,
                tailable: true
            })
        ]);
    }
    if (config.console) {
        const consoleTransport = new winston_1.transports.Console({
            format: getLoggerFormat(config, scopeBag, true)
        });
        transports.push(consoleTransport);
    }
    return transports;
}
exports.getLoggerTransports = getLoggerTransports;
function enableProdMode(logger) {
    process.on('uncaughtException', (err) => {
        logger.error(err, 'UncaughtException');
    });
    process.on('unhandledRejection', (err) => {
        logger.error(err, 'UnhandledRejection');
    });
}
exports.enableProdMode = enableProdMode;
async function buildLogger(rawConfig, env = 'production') {
    const config = (0, config_1.validateConfig)(rawConfig, exports.LoggerConfigSchema);
    const scopeBag = {
        scopes: [],
        maxLength: 0
    };
    (0, winston_1.addColors)({
        scope: 'yellow'
    });
    const options = {
        level: config.level,
        transports: getLoggerTransports(config, scopeBag)
    };
    const nativeLogger = (0, winston_1.createLogger)(options);
    let purger;
    if (config.purge) {
        purger = (0, purge_builder_1.buildLoggerPurger)(config.path, config.purge);
    }
    const logger = new root_logger_1.RootLogger(nativeLogger, scopeBag, config.serializeError, purger);
    if ((0, config_1.isProd)(env)) {
        enableProdMode(logger);
    }
    await (0, fs_1.prepareDir)(config.path);
    return logger;
}
exports.buildLogger = buildLogger;
