import { join } from "path";
import stripAnsi from "strip-ansi";
import winston from "winston";
import DailyRotateFile from "winston-daily-rotate-file";
import { parseClientEntry } from "./clients/TorrentClient.js";
import { appDir } from "./configuration.js";
import { LOGS_FOLDER } from "./constants.js";
import { CrossSeedError } from "./errors.js";
export var Label;
(function (Label) {
    Label["QBITTORRENT"] = "qbittorrent";
    Label["RTORRENT"] = "rtorrent";
    Label["TRANSMISSION"] = "transmission";
    Label["DELUGE"] = "deluge";
    Label["DECIDE"] = "decide";
    Label["PREFILTER"] = "prefilter";
    Label["CONFIG"] = "config";
    Label["TORZNAB"] = "torznab";
    Label["SERVER"] = "server";
    Label["SCHEDULER"] = "scheduler";
    Label["SEARCH"] = "search";
    Label["RSS"] = "rss";
    Label["ANNOUNCE"] = "announce";
    Label["WEBHOOK"] = "webhook";
    Label["INJECT"] = "inject";
    Label["PERF"] = "perf";
    Label["CLEANUP"] = "cleanup";
    Label["ARRS"] = "arrs";
    Label["RADARR"] = "radarr";
    Label["SONARR"] = "sonarr";
    Label["AUTH"] = "auth";
    Label["INDEX"] = "index";
})(Label || (Label = {}));
export let logger;
const REDACTED_MSG = "[REDACTED]";
const ERROR_PREFIX_REGEX = /^\s*error:\s*/i;
const SUB_SECOND_TS_REGEX = /\.\d{3,}$/;
function redactUrlPassword(message, urlStr) {
    let url;
    try {
        url = new URL(urlStr);
        if (url.password) {
            const urlDecodedPassword = decodeURIComponent(url.password);
            const urlEncodedPassword = encodeURIComponent(url.password);
            message = message.split(url.password).join(REDACTED_MSG);
            message = message.split(urlDecodedPassword).join(REDACTED_MSG);
            message = message.split(urlEncodedPassword).join(REDACTED_MSG);
        }
    }
    catch {
        // do nothing
    }
    return message;
}
function redactMessage(message, options) {
    if (typeof message !== "string") {
        return message;
    }
    let ret = message;
    ret = ret.replace(/key=[a-zA-Z0-9]+/g, `key=${REDACTED_MSG}`);
    ret = ret.replace(/pass=[a-zA-Z0-9]+/g, `pass=${REDACTED_MSG}`);
    ret = ret.replace(/(?:(?:auto|download)[./]\d+[./])([a-zA-Z0-9]+)/g, (match, key) => match.replace(key, REDACTED_MSG));
    ret = ret.replace(/(?:\d+[./](?:auto|download)[./])([a-zA-Z0-9]+)/g, (match, key) => match.replace(key, REDACTED_MSG));
    ret = ret.replace(/apiKey: '.+'/g, `apiKey: ${REDACTED_MSG}`);
    ret = ret.replace(/\/notification\/crossSeed\/[a-zA-Z-0-9_-]+/g, `/notification/crossSeed/${REDACTED_MSG}`);
    for (const [key, value] of Object.entries(options)) {
        if (key.endsWith("Url") && typeof value === "string") {
            ret = redactUrlPassword(ret, value);
        }
        if (key === "torrentClients" && Array.isArray(value)) {
            for (const clientEntry of value) {
                ret = redactUrlPassword(ret, parseClientEntry(clientEntry).url);
            }
        }
    }
    return ret;
}
function stripAnsiChars(message) {
    if (typeof message !== "string") {
        return message;
    }
    return stripAnsi(message);
}
const logOnceCache = new Set();
export function logOnce(cacheKey, cb, ttl) {
    if (!logOnceCache.has(cacheKey)) {
        logOnceCache.add(cacheKey);
        cb();
        if (ttl) {
            setTimeout(() => {
                logOnceCache.delete(cacheKey);
            }, ttl).unref();
        }
    }
}
export function initializeLogger(options) {
    logger = winston.createLogger({
        level: "info",
        format: winston.format.combine(winston.format.timestamp({
            format: "YYYY-MM-DD HH:mm:ss.SSS",
        }), winston.format.errors({ stack: true }), winston.format.splat(), winston.format.printf(({ level, message, label, timestamp, stack, cause }) => {
            const msg = !stack
                ? `${message}${cause ? `\n${cause}` : ""}`
                : `${stack}${cause ? `\n${cause}` : ""}`.replace(ERROR_PREFIX_REGEX, "");
            return `${timestamp} ${level}: ${label ? `[${label}] ` : ""}${stripAnsiChars(redactMessage(msg, options))}`;
        })),
        transports: [
            new DailyRotateFile({
                filename: "error.%DATE%.log",
                createSymlink: true,
                symlinkName: "error.current.log",
                dirname: join(appDir(), LOGS_FOLDER),
                maxFiles: "14d",
                level: "error",
            }),
            new DailyRotateFile({
                filename: "info.%DATE%.log",
                createSymlink: true,
                symlinkName: "info.current.log",
                dirname: join(appDir(), LOGS_FOLDER),
                maxFiles: "14d",
            }),
            new DailyRotateFile({
                filename: "verbose.%DATE%.log",
                createSymlink: true,
                symlinkName: "verbose.current.log",
                dirname: join(appDir(), LOGS_FOLDER),
                maxFiles: "14d",
                level: "silly",
            }),
            new winston.transports.Console({
                level: options.verbose ? "silly" : "info",
                format: winston.format.combine(winston.format.errors({ stack: true }), winston.format.splat(), winston.format.colorize(), winston.format.printf(({ level, message, label, timestamp, stack, cause, }) => {
                    timestamp = timestamp.replace(SUB_SECOND_TS_REGEX, "");
                    const msg = !stack
                        ? `${message}${cause ? `\n${cause}` : ""}`
                        : `${stack}${cause ? `\n${cause}` : ""}`.replace(ERROR_PREFIX_REGEX, "");
                    return `${timestamp} ${level}: ${label ? `[${label}] ` : ""}${redactMessage(msg, options)}`;
                })),
            }),
        ],
    });
}
export function exitOnCrossSeedErrors(error) {
    if (logger) {
        logger.error(error);
    }
    else {
        console.error(error);
    }
    if (error instanceof CrossSeedError) {
        process.exitCode = 1;
        return;
    }
    throw error;
}
//# sourceMappingURL=logger.js.map