import winston from "winston";
import DailyRotateFile from "winston-daily-rotate-file";
import path from "path";
import type { Err } from "@pkg/result";
import util from "util";

process.on("warning", (warning) => {
  if (warning.message.includes("punycode")) {
    return;
  }
  console.warn(warning);
});

const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,
};

const colors = {
  error: "red",
  warn: "yellow",
  info: "green",
  http: "magenta",
  debug: "white",
};

const level = () => {
  const env = process.env.NODE_ENV || "development";
  return env === "development" ? "debug" : "warn";
};

const format = winston.format.combine(
  winston.format.errors({ stack: true }),
  winston.format.timestamp({ format: "YYYY-MM-DD HH:mm:ss:ms" }),
  winston.format.colorize({ all: true }),
  winston.format.printf((info) => {
    const { level, message, timestamp, ...extra } = info;

    let formattedMessage = "";
    if (message instanceof Error) {
      formattedMessage = message.stack || message.message;
    } else if (typeof message === "object") {
      formattedMessage = util.inspect(message, { depth: null, colors: true });
    } else {
      formattedMessage = message as any as string;
    }

    // Handle extra fields (if any)
    const formattedExtra =
      Object.keys(extra).length > 0
        ? `\n${util.inspect(extra, { depth: null, colors: true })}`
        : "";

    return `[${level}] ${timestamp}: ${formattedMessage}${formattedExtra}`;
  }),
);

const transports = [
  new winston.transports.Console(),

  new DailyRotateFile({
    filename: path.join("logs", "error-%DATE%.log"),
    datePattern: "YYYY-MM-DD",
    level: "error",
    maxSize: "5m",
    maxFiles: "14d",
    format: format,
  }),

  new DailyRotateFile({
    filename: path.join("logs", "all-%DATE%.log"),
    datePattern: "YYYY-MM-DD",
    maxSize: "5m",
    maxFiles: "14d",
    format: format,
  }),
];

winston.addColors(colors);

const Logger = winston.createLogger({
  level: level(),
  levels,
  format,
  transports,
});

const stream = { write: (message: string) => Logger.http(message.trim()) };

function getError(payload: Err, error?: any) {
  Logger.error(JSON.stringify({ payload, error }, null, 2));
  return {
    code: payload.code,
    message: payload.message,
    userHint: payload.userHint,
    detail: payload.detail,
    error: error instanceof Error ? error.message : error,
    actionable: payload.actionable,
  } as Err;
}

export { Logger, stream, getError };
