import winston from 'winston';
import DailyRotateFile from 'winston-daily-rotate-file';
import path from 'path';

// Log interface with additional fields
interface LogInfo extends winston.LogEntry {
  tag?: string;
  context?: Record<string, unknown>;
}

// Create custom format
const customFormat = winston.format.printf(({ level, message, timestamp, tag, context }) => {
  const contextStr = context ? ` | context: ${JSON.stringify(context)}` : '';
  return `[${timestamp}] [${tag || 'main'}] [${level.toUpperCase()}]: ${message}${contextStr}`;
});

// Logger configuration
const logger = winston.createLogger({
  level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
  format: winston.format.combine(
    winston.format.timestamp({
      format: 'YYYY-MM-DD HH:mm:ss'
    }),
    winston.format.errors({ stack: true }),
    customFormat
  ),
  transports: [
    // File logging with rotation
    new DailyRotateFile({
      dirname: path.join(process.cwd(), 'logs'),
      filename: 'app-%DATE%.log',
      datePattern: 'YYYY-MM-DD',
      zippedArchive: true,
      maxSize: '20m',
      maxFiles: '14d',
      level: 'info'
    }),
    // Console logging with colors
    new winston.transports.Console({
      format: winston.format.combine(
        winston.format.colorize(),
        customFormat
      )
    })
  ]
});

// Handle unhandled exceptions and promises
logger.exceptions.handle(
  new winston.transports.File({ filename: path.join(process.cwd(), 'logs', 'exceptions.log') })
);
logger.rejections.handle(
  new winston.transports.File({ filename: path.join(process.cwd(), 'logs', 'rejections.log') })
);

// Logger method types
type LogLevel = 'error' | 'warn' | 'info' | 'debug';
type LogMethod = (tag: string, message: string, context?: Record<string, unknown>) => void;

// Create methods for different log levels
const createLogMethod = (level: LogLevel): LogMethod => {
  return (tag: string, message: string, context?: Record<string, unknown>) => {
    logger.log({
      level,
      message,
      tag,
      context
    } as LogInfo);
  };
};

// Export logger interface
export const log = {
  error: createLogMethod('error'),
  warn: createLogMethod('warn'),
  info: createLogMethod('info'),
  debug: createLogMethod('debug'),
  // Method for logging unhandled errors
  fatal: (error: Error, context?: Record<string, unknown>) => {
    logger.error({
      level: 'error',
      message: error.message,
      tag: 'uncaught',
      context: {
        ...context,
        stack: error.stack
      }
    } as LogInfo);
  }
};

// Configure unhandled error handlers
process.on('uncaughtException', (error) => {
  log.fatal(error);
  process.exit(1);
});

process.on('unhandledRejection', (reason) => {
  if (reason instanceof Error) {
    log.fatal(reason);
  } else {
    log.error('unhandledRejection', 'Unhandled promise rejection', { reason });
  }
});

export default log; 