import winston, { format, transports } from "winston";

/**
 * Módulo de logging centralizado usando Winston.
 *
 * Proporciona cuatro canales de log independientes:
 * - **General** (`info` / `error`): consola + archivos `logs/all/` y `logs/error/`
 * - **Bancamiga** (`bancamiga`): archivo `logs/bancamiga/` para pagos Bancamiga
 * - **Operations** (`operation`): archivo `logs/operations/` para operaciones de crédito
 *
 * Cada canal puede activarse/desactivarse en tiempo de ejecución con las funciones
 * `enable*` / `disable*` para facilitar el debugging sin reiniciar el servidor.
 *
 * Los archivos de log se nombran con la fecha del día (YYYY-MM-DD.log), por lo que
 * se crean nuevos archivos automáticamente cada día.
 */

// Flags de control para activar/desactivar cada canal de logging
let ENABLE_LOGGING = true;
let ENABLE_ERROR_LOGGING = true;
let ENABLE_PAGO_LOGGING = true;
let ENABLE_OPERATION_LOGGING = true;

// Formato de línea: "YYYY-MM-DD HH:mm:ss level: mensaje"
const logFormat = format.printf(
  (info) => `${info.timestamp} ${info.level}: ${info.message}`,
);

// Logger principal: escribe en consola, en logs/error/ y en logs/all/
const logger = winston.createLogger({
  level: "info",
  format: format.combine(
    format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
    format.errors({ stack: true }),
    format.json(),
    format.prettyPrint(),
  ),
  transports: [
    new transports.Console({
      format: format.combine(format.colorize(), logFormat),
    }),
    //
    // - Write all logs with importance level of `error` or less to `logs/error.log`
    // - Write all logs with importance level of `info` or less to `logs/all.log`
    //
    new transports.File({
      filename: `logs/error/${new Date().toISOString().split("T")[0]}.log`,
      level: "error",
      format: logFormat,
    }),
    new transports.File({
      filename: `logs/all/${new Date().toISOString().split("T")[0]}.log`,
      level: "info",
      format: logFormat,
    }),
  ],
});

/**
 * Registra un mensaje informativo en el logger principal.
 * Si `obj` es proporcionado, se serializa como JSON junto al mensaje.
 *
 * @param message - Texto del mensaje a registrar
 * @param obj - Objeto adicional a incluir en el log (opcional)
 */
export const info = (message: string, obj?: any) => {
  if (ENABLE_LOGGING) {
    if (obj) {
      logger.info(`${message} ${JSON.stringify(obj)}`);
    } else {
      logger.info(message);
    }
  }
};

/**
 * Registra un mensaje de error en el logger principal.
 * Si `obj` es una instancia de `Error`, se usa su `message`; de lo contrario se serializa.
 *
 * @param message - Texto del mensaje de error
 * @param obj - Error o datos adicionales a incluir (opcional)
 */
export const error = (message: string, obj?: unknown) => {
  if (ENABLE_LOGGING && ENABLE_ERROR_LOGGING) {
    if (obj instanceof Error) {
      logger.error(`${message} ${obj.message}`); // ${err.stack}
    } else if (obj) {
      logger.error(`${message} ${JSON.stringify(obj)}`);
    } else {
      logger.error(message);
    }
  }
};

/**
 * Registra un mensaje en el canal exclusivo de pagos Bancamiga.
 * Escribe en `logs/bancamiga/YYYY-MM-DD.log`.
 * Solo se ejecuta si `ENABLE_PAGO_LOGGING` está activo.
 *
 * @param message - Texto del mensaje a registrar
 * @param obj - Objeto adicional a incluir en el log (opcional)
 */
export const bancamiga = (message: string, obj?: any) => {
  if (ENABLE_LOGGING && ENABLE_PAGO_LOGGING) {
    const pagoLogger = winston.createLogger({
      format: format.combine(
        format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
        logFormat,
      ),
      transports: [
        new transports.File({
          filename: `logs/bancamiga/${
            new Date().toISOString().split("T")[0]
          }.log`,
          level: "info",
        }),
      ],
    });

    if (obj) {
      pagoLogger.info(`${message} ${JSON.stringify(obj)}`);
    } else {
      pagoLogger.info(message);
    }
  }
};

/**
 * Registra un mensaje en el canal exclusivo de operaciones de crédito.
 * Escribe en `logs/operations/YYYY-MM-DD.log`.
 * Solo se ejecuta si `ENABLE_OPERATION_LOGGING` está activo.
 *
 * @param message - Texto del mensaje a registrar
 * @param obj - Objeto adicional a incluir en el log (opcional)
 */
export const operation = (message: string, obj?: any) => {
  if (ENABLE_LOGGING && ENABLE_OPERATION_LOGGING) {
    const operationLogger = winston.createLogger({
      format: format.combine(
        format.timestamp({ format: "YYYY-MM-DD HH:mm:ss" }),
        logFormat,
      ),
      transports: [
        new transports.File({
          filename: `logs/operations/${
            new Date().toISOString().split("T")[0]
          }.log`,
          level: "info",
        }),
      ],
    });

    if (obj) {
      operationLogger.info(`${message} ${JSON.stringify(obj)}`);
    } else {
      operationLogger.info(message);
    }
  }
};

/** Activa todos los canales de logging */
export const enableLogging = () => {
  ENABLE_LOGGING = true;
};

/** Desactiva todos los canales de logging */
export const disableLogging = () => {
  ENABLE_LOGGING = false;
};

/** Activa el canal de errores */
export const enableErrorLogging = () => {
  ENABLE_ERROR_LOGGING = true;
};

/** Desactiva el canal de errores */
export const disableErrorLogging = () => {
  ENABLE_ERROR_LOGGING = false;
};

/** Activa el canal de pagos Bancamiga */
export const enablePagoLogging = () => {
  ENABLE_PAGO_LOGGING = true;
};

/** Desactiva el canal de pagos Bancamiga */
export const disablePagoLogging = () => {
  ENABLE_PAGO_LOGGING = false;
};

/** Activa el canal de operaciones de crédito */
export const enableOperationLogging = () => {
  ENABLE_OPERATION_LOGGING = true;
};

/** Desactiva el canal de operaciones de crédito */
export const disableOperationLogging = () => {
  ENABLE_OPERATION_LOGGING = false;
};
