import { WinstonModuleOptions } from 'nest-winston';
import * as winston from 'winston';
import { utilities as nestWinstonModuleUtilities } from 'nest-winston';

// Custom format to sanitize PII
const piiSanitizer = winston.format((info) => {
  const piiPatterns = {
    email: /[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}/g,
    phone: /(\+?\d{1,3}[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}/g,
    ssn: /\b\d{3}-?\d{2}-?\d{4}\b/g,
    creditCard: /\b\d{4}[-\s]?\d{4}[-\s]?\d{4}[-\s]?\d{4}\b/g,
    ipv4: /\b(?:\d{1,3}\.){3}\d{1,3}\b/g,
  };

  const sanitize = (text: string): string => {
    if (typeof text !== 'string') return text;

    let sanitized = text;
    sanitized = sanitized.replace(piiPatterns.email, '[EMAIL_REDACTED]');
    sanitized = sanitized.replace(piiPatterns.phone, '[PHONE_REDACTED]');
    sanitized = sanitized.replace(piiPatterns.ssn, '[SSN_REDACTED]');
    sanitized = sanitized.replace(piiPatterns.creditCard, '[CC_REDACTED]');
    sanitized = sanitized.replace(piiPatterns.ipv4, '[IP_REDACTED]');

    return sanitized;
  };

  // Sanitize message
  if (info.message && typeof info.message === 'string') {
    info.message = sanitize(info.message);
  }

  // Sanitize metadata
  if (info.context && typeof info.context === 'object') {
    Object.keys(info.context).forEach((key) => {
      if (typeof info.context[key] === 'string') {
        info.context[key] = sanitize(info.context[key]);
      }
    });
  }

  return info;
});

export const winstonConfig: WinstonModuleOptions = {
  transports: [
    // Console transport for development
    new winston.transports.Console({
      level: process.env.LOG_LEVEL || 'info',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.ms(),
        piiSanitizer(),
        nestWinstonModuleUtilities.format.nestLike('MaternalApp', {
          colors: true,
          prettyPrint: true,
        }),
      ),
    }),

    // File transport for errors
    new winston.transports.File({
      filename: 'logs/error.log',
      level: 'error',
      format: winston.format.combine(
        winston.format.timestamp(),
        piiSanitizer(),
        winston.format.json(),
      ),
      maxsize: 5242880, // 5MB
      maxFiles: 5,
    }),

    // File transport for all logs
    new winston.transports.File({
      filename: 'logs/combined.log',
      format: winston.format.combine(
        winston.format.timestamp(),
        piiSanitizer(),
        winston.format.json(),
      ),
      maxsize: 5242880, // 5MB
      maxFiles: 10,
    }),

    // File transport for audit logs (no PII sanitization)
    new winston.transports.File({
      filename: 'logs/audit.log',
      level: 'info',
      format: winston.format.combine(
        winston.format.timestamp(),
        winston.format.json(),
        winston.format((info: any) => {
          // Only include audit-related logs
          return info.context?.isAudit ? info : false;
        })(),
      ),
      maxsize: 5242880, // 5MB
      maxFiles: 30, // Keep longer for compliance
    }),
  ],

  // Global exception handler
  exceptionHandlers: [
    new winston.transports.File({
      filename: 'logs/exceptions.log',
      format: winston.format.combine(
        winston.format.timestamp(),
        piiSanitizer(),
        winston.format.json(),
      ),
    }),
  ],

  // Global rejection handler
  rejectionHandlers: [
    new winston.transports.File({
      filename: 'logs/rejections.log',
      format: winston.format.combine(
        winston.format.timestamp(),
        piiSanitizer(),
        winston.format.json(),
      ),
    }),
  ],
};

// Production configuration (can be enabled via environment variable)
if (process.env.NODE_ENV === 'production') {
  // Remove console transport in production
  winstonConfig.transports = (winstonConfig.transports as any[]).filter(
    (transport) => !(transport instanceof winston.transports.Console),
  );

  // Add production-specific transports (e.g., CloudWatch, Elasticsearch)
  // Example: CloudWatch
  // winstonConfig.transports.push(
  //   new WinstonCloudWatch({
  //     logGroupName: process.env.CLOUDWATCH_LOG_GROUP,
  //     logStreamName: `${process.env.CLOUDWATCH_LOG_STREAM}-${Date.now()}`,
  //     awsRegion: process.env.AWS_REGION,
  //     jsonMessage: true,
  //   })
  // );
}
