const winston = require('winston');
const DailyRotateFile = require('winston-daily-rotate-file');
const path = require('path');

// Definir niveles de log personalizados
const levels = {
  error: 0,
  warn: 1,
  info: 2,
  http: 3,
  debug: 4,
};

// Definir colores para cada nivel
const colors = {
  error: 'red',
  warn: 'yellow',
  info: 'green',
  http: 'magenta',
  debug: 'blue',
};

// Agregar colores a winston
winston.addColors(colors);

// Determinar el nivel de log según el entorno
const level = () => {
  const env = process.env.NODE_ENV || 'development';
  const isDevelopment = env === 'development';
  return isDevelopment ? 'debug' : 'warn';
};

// Formato personalizado para logs
const format = winston.format.combine(
  winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss:ms' }),
  winston.format.errors({ stack: true }),
  winston.format.splat(),
  winston.format.json(),
  winston.format.printf((info) => {
    const { timestamp, level, message, stack, ...meta } = info;
    
    let log = `${timestamp} [${level.toUpperCase()}]: ${message}`;
    
    // Agregar metadata si existe
    if (Object.keys(meta).length > 0) {
      log += ` ${JSON.stringify(meta)}`;
    }
    
    // Agregar stack trace si existe
    if (stack) {
      log += `\n${stack}`;
    }
    
    return log;
  })
);

// Formato para consola con colores
const consoleFormat = winston.format.combine(
  winston.format.colorize({ all: true }),
  winston.format.timestamp({ format: 'YYYY-MM-DD HH:mm:ss' }),
  winston.format.printf((info) => {
    const { timestamp, level, message, stack, ...meta } = info;
    
    let log = `${timestamp} [${level}]: ${message}`;
    
    if (Object.keys(meta).length > 0) {
      log += ` ${JSON.stringify(meta, null, 2)}`;
    }
    
    if (stack) {
      log += `\n${stack}`;
    }
    
    return log;
  })
);

// Configuración de transports
const transports = [
  // Console transport
  new winston.transports.Console({
    format: consoleFormat,
  }),

  // Error logs - Rotación diaria
  new DailyRotateFile({
    filename: path.join('logs', 'error-%DATE%.log'),
    datePattern: 'YYYY-MM-DD',
    level: 'error',
    maxSize: '20m',
    maxFiles: '30d',
    format: format,
    zippedArchive: true,
  }),

  // Combined logs - Rotación diaria
  new DailyRotateFile({
    filename: path.join('logs', 'combined-%DATE%.log'),
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '30d',
    format: format,
    zippedArchive: true,
  }),

  // HTTP logs - Rotación diaria
  new DailyRotateFile({
    filename: path.join('logs', 'http-%DATE%.log'),
    datePattern: 'YYYY-MM-DD',
    level: 'http',
    maxSize: '20m',
    maxFiles: '14d',
    format: format,
    zippedArchive: true,
  }),

  // Security logs - Para eventos de seguridad
  new DailyRotateFile({
    filename: path.join('logs', 'security-%DATE%.log'),
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '90d', // Mantener logs de seguridad por 90 días
    format: format,
    zippedArchive: true,
  }),

  // Audit logs - Para auditoría
  new DailyRotateFile({
    filename: path.join('logs', 'audit-%DATE%.log'),
    datePattern: 'YYYY-MM-DD',
    maxSize: '20m',
    maxFiles: '90d',
    format: format,
    zippedArchive: true,
  }),
];

// Crear el logger
const logger = winston.createLogger({
  level: level(),
  levels,
  format,
  transports,
  exitOnError: false,
});

// Métodos personalizados para diferentes tipos de logs

// Log de seguridad
logger.security = (message, meta = {}) => {
  logger.log({
    level: 'warn',
    message: `[SECURITY] ${message}`,
    ...meta,
    timestamp: new Date().toISOString(),
  });
};

// Log de auditoría
logger.audit = (action, user, resource, meta = {}) => {
  logger.log({
    level: 'info',
    message: `[AUDIT] ${action}`,
    user,
    resource,
    ...meta,
    timestamp: new Date().toISOString(),
  });
};

// Log de autenticación
logger.auth = (message, meta = {}) => {
  logger.log({
    level: 'info',
    message: `[AUTH] ${message}`,
    ...meta,
    timestamp: new Date().toISOString(),
  });
};

// Log de base de datos
logger.database = (message, meta = {}) => {
  logger.log({
    level: 'debug',
    message: `[DATABASE] ${message}`,
    ...meta,
    timestamp: new Date().toISOString(),
  });
};

// Log de API requests
logger.request = (req, res, responseTime) => {
  const { method, originalUrl, ip, headers } = req;
  const { statusCode } = res;
  
  logger.http(`${method} ${originalUrl}`, {
    method,
    url: originalUrl,
    statusCode,
    ip,
    userAgent: headers['user-agent'],
    responseTime: `${responseTime}ms`,
    timestamp: new Date().toISOString(),
  });
};

// Log de errores con contexto
logger.errorWithContext = (error, context = {}) => {
  logger.error(error.message, {
    error: {
      name: error.name,
      message: error.message,
      stack: error.stack,
    },
    context,
    timestamp: new Date().toISOString(),
  });
};

// Middleware de Morgan personalizado para Winston
logger.stream = {
  write: (message) => {
    logger.http(message.trim());
  },
};

// Función para limpiar logs antiguos manualmente si es necesario
logger.cleanOldLogs = (days = 30) => {
  const fs = require('fs');
  const logsDir = path.join(__dirname, '../../logs');
  
  if (!fs.existsSync(logsDir)) {
    return;
  }

  const files = fs.readdirSync(logsDir);
  const now = Date.now();
  const maxAge = days * 24 * 60 * 60 * 1000;

  files.forEach(file => {
    const filePath = path.join(logsDir, file);
    const stats = fs.statSync(filePath);
    const age = now - stats.mtime.getTime();

    if (age > maxAge) {
      fs.unlinkSync(filePath);
      logger.info(`Log antiguo eliminado: ${file}`);
    }
  });
};

// Crear directorio de logs si no existe
const fs = require('fs');
const logsDir = path.join(__dirname, '../../logs');
if (!fs.existsSync(logsDir)) {
  fs.mkdirSync(logsDir, { recursive: true });
}

module.exports = logger;