/**
 * 日志系统模块
 * 
 * 功能描述：
 * - 提供统一的日志记录服务，支持多种日志级别
 * - 集成 Pino 高性能日志库，支持降级到 NestJS 内置 Logger
 * - 自动过滤敏感信息，保护系统安全
 * - 支持请求上下文绑定，便于链路追踪
 * 
 * 职责分离：
 * - 日志记录：提供统一的日志记录接口和方法
 * - 级别控制：根据环境动态调整日志输出级别
 * - 安全过滤：自动过滤敏感信息防止数据泄露
 * - 上下文绑定：支持请求上下文关联和链路追踪
 * 
 * 最近修改：
 * - 2026-01-07: 代码规范优化 - 修复常量命名规范，完善注释文档，重构log方法提升可维护性
 * 
 * 依赖模块：
 * - ConfigService: 环境配置服务
 * - PinoLogger: 高性能日志库（可选）
 * - Logger: NestJS 内置日志服务（降级使用）
 * 
 * @author moyin
 * @version 1.0.1
 * @since 2025-12-13
 * @lastModified 2026-01-07
 */

import { Injectable, Logger, Inject, Optional } from '@nestjs/common';
import { PinoLogger } from 'nestjs-pino';
import { ConfigService } from '@nestjs/config';

/**
 * 日志级别枚举
 * 
 * 级别说明：
 * - trace: 极细粒度调试信息
 * - debug: 调试信息，开发环境使用
 * - info: 重要业务操作记录
 * - warn: 警告信息，需要关注但不影响正常流程
 * - error: 错误信息，影响功能正常使用
 * - fatal: 致命错误，可能导致系统不可用
 */
export type LogLevel = 'debug' | 'info' | 'warn' | 'error' | 'fatal' | 'trace';

/**
 * 日志上下文接口
 * 
 * 用于补充日志的上下文信息，便于问题排查和链路追踪
 */
export interface LogContext {
  /** 请求 ID，用于链路追踪 */
  reqId?: string;
  /** 模块名称，标识日志来源 */
  module?: string;
  /** 用户 ID，关联用户行为 */
  userId?: string;
  /** 操作类型，描述具体操作 */
  operation?: string;
  /** 时间戳，记录操作时间 */
  timestamp?: string;
  /** 执行时长，性能监控 */
  duration?: number;
  /** 自定义扩展字段 */
  [key: string]: any;
}

/**
 * 日志选项接口
 * 
 * 定义日志记录时的参数结构
 */
export interface LogOptions {
  /** 日志消息内容 */
  message: string;
  /** 日志上下文信息 */
  context?: LogContext;
  /** 错误堆栈信息（仅用于 error/fatal 级别） */
  stack?: string;
}

/**
 * 应用日志服务类
 * 
 * 职责：
 * - 提供统一的日志记录接口
 * - 管理不同环境下的日志级别控制
 * - 自动过滤敏感信息，防止数据泄露
 * - 支持请求上下文绑定，便于问题追踪
 * 
 * 主要方法：
 * - debug(): 记录调试信息
 * - info(): 记录重要业务操作
 * - warn(): 记录警告信息
 * - error(): 记录错误信息
 * - fatal(): 记录致命错误
 * - trace(): 记录追踪信息
 * - bindRequest(): 绑定请求上下文
 * 
 * 使用场景：
 * - 业务操作日志记录
 * - 系统异常监控
 * - 性能监控和问题排查
 * - 安全审计和行为追踪
 */
@Injectable()
export class AppLoggerService {
  // 底层日志实例（优先 Pino，无则用内置 Logger）
  private readonly logger: PinoLogger | Logger;
  // 日志级别开关（生产环境可动态调整）
  private readonly enableLevels: Record<LogLevel, boolean>;

  constructor(
    // 注入 Pino Logger（可选，无则降级到内置 Logger）
    @Optional() @Inject(PinoLogger) private readonly pinoLogger: PinoLogger,
    private readonly configService: ConfigService,
  ) {
    // 初始化底层日志实例
    this.logger = this.pinoLogger || new Logger('AppLogger');

    // 从环境变量读取启用的日志级别（默认开发环境全开启，生产环境仅开启 warn/error/fatal）
    const env = this.configService.get('NODE_ENV', 'development');
    this.enableLevels = {
      trace: env === 'development',
      debug: env === 'development',
      info: env !== 'production',
      warn: true,
      error: true,
      fatal: true,
    };
  }

  /**
   * 通用日志记录方法
   * 
   * 功能描述：
   * 封装所有日志级别的核心记录逻辑，统一处理日志格式化、上下文补充和敏感信息过滤
   * 
   * 业务逻辑：
   * 1. 检查日志级别是否启用
   * 2. 补充默认上下文信息
   * 3. 合并自定义上下文
   * 4. 过滤敏感信息
   * 5. 构造标准日志数据
   * 6. 根据底层日志实例类型选择合适的输出方式
   * 
   * @param level 日志级别，决定日志的重要程度和输出策略
   * @param options 日志选项，包含消息内容、上下文信息等
   * @private
   */
  private log(level: LogLevel, options: LogOptions): void {
    // 过滤禁用的日志级别（生产环境不输出 debug/trace）
    if (!this.enableLevels[level]) return;

    // 构建完整的日志数据
    const logData = this.buildLogData(options);

    // 输出日志
    this.outputLog(level, logData, options.stack);
  }

  /**
   * 构建日志数据
   * 
   * 功能描述：
   * 构建包含上下文信息和敏感信息过滤的完整日志数据
   * 
   * @param options 日志选项
   * @returns 构建完成的日志数据
   * @private
   */
  private buildLogData(options: LogOptions) {
    // 1. 补充默认上下文
    const defaultContext: LogContext = {
      module: options.context?.module || 'Unknown',
      reqId: options.context?.reqId || 'no-req-id',
      userId: options.context?.userId || 'anonymous',
      timestamp: new Date().toISOString(),
      app: this.configService.get('APP_NAME', 'nest-app'),
    };

    // 2. 合并上下文（自定义上下文覆盖默认）
    const context = { ...defaultContext, ...options.context };

    // 3. 敏感信息过滤（避免日志泄露密码/Token）
    this.redactSensitiveData(context);

    // 4. 构造日志数据
    return {
      message: options.message,
      context,
    };
  }

  /**
   * 输出日志
   * 
   * 功能描述：
   * 根据底层日志实例类型选择合适的输出方式
   * 
   * @param level 日志级别
   * @param logData 日志数据
   * @param stack 错误堆栈（可选）
   * @private
   */
  private outputLog(level: LogLevel, logData: any, stack?: string): void {
    const finalLogData = {
      ...logData,
      ...(stack ? { stack } : {}), // 仅错误级别携带栈信息
    };

    if (this.pinoLogger) {
      this.outputToPino(level, finalLogData);
    } else {
      this.outputToBuiltInLogger(level, finalLogData, stack);
    }
  }

  /**
   * 输出到 Pino 日志库
   * 
   * @param level 日志级别
   * @param logData 日志数据
   * @private
   */
  private outputToPino(level: LogLevel, logData: any): void {
    switch (level) {
      case 'debug':
        this.pinoLogger.debug(logData.message, logData);
        break;
      case 'info':
        this.pinoLogger.info(logData.message, logData);
        break;
      case 'warn':
        this.pinoLogger.warn(logData.message, logData);
        break;
      case 'error':
        this.pinoLogger.error(logData.message, logData);
        break;
      case 'fatal':
        this.pinoLogger.fatal(logData.message, logData);
        break;
      case 'trace':
        this.pinoLogger.trace(logData.message, logData);
        break;
      default:
        this.pinoLogger.info(logData.message, logData);
    }
  }

  /**
   * 输出到内置 Logger
   * 
   * @param level 日志级别
   * @param logData 日志数据
   * @param stack 错误堆栈（可选）
   * @private
   */
  private outputToBuiltInLogger(level: LogLevel, logData: any, stack?: string): void {
    const builtInLogger = this.logger as Logger;
    const contextString = JSON.stringify(logData.context);
    
    switch (level) {
      case 'debug':
        builtInLogger.debug(logData.message, contextString);
        break;
      case 'info':
        builtInLogger.log(logData.message, contextString); // 内置 Logger 使用 log 方法代替 info
        break;
      case 'warn':
        builtInLogger.warn(logData.message, contextString);
        break;
      case 'error':
      case 'fatal': // fatal 级别降级为 error
        builtInLogger.error(logData.message, stack || '', contextString);
        break;
      case 'trace':
        builtInLogger.verbose(logData.message, contextString); // trace 级别降级为 verbose
        break;
      default:
        builtInLogger.log(logData.message, contextString);
    }
  }

  /**
   * 敏感信息过滤方法
   * 
   * 功能描述：
   * 递归扫描日志数据中的敏感字段，将其替换为占位符，防止敏感信息泄露
   * 
   * 业务逻辑：
   * 1. 定义敏感字段关键词列表
   * 2. 遍历数据对象的所有键
   * 3. 检查键名是否包含敏感关键词
   * 4. 将敏感字段值替换为 [REDACTED]
   * 5. 递归处理嵌套对象
   * 
   * @param data 需要过滤的日志数据对象
   * @private
   */
  private redactSensitiveData(data: Record<string, any>): void {
    const sensitiveKeys = ['password', 'token', 'secret', 'authorization', 'cardNo'];
    Object.keys(data).forEach((key) => {
      if (sensitiveKeys.some((sk) => key.toLowerCase().includes(sk))) {
        data[key] = '[REDACTED]'; // 替换为占位符，或直接删除
      }
      // 递归过滤嵌套对象
      if (typeof data[key] === 'object' && data[key] !== null) {
        this.redactSensitiveData(data[key]);
      }
    });
  }

  // ========== 公共日志记录方法 ==========
  
  /**
   * 记录调试日志
   * 
   * 功能描述：
   * 记录详细的调试信息，主要用于开发环境的问题排查
   * 
   * 使用场景：
   * - 方法调用参数记录
   * - 中间计算结果输出
   * - 详细的执行流程追踪
   * 
   * 注意事项：
   * - 仅在开发环境启用
   * - 生产环境自动禁用以提高性能
   * 
   * @param message 调试消息内容
   * @param context 调试上下文信息
   * 
   * @example
   * ```typescript
   * this.logger.debug('开始处理用户请求', {
   *   module: 'UserService',
   *   operation: 'getUserInfo',
   *   userId: 'user123',
   *   params: { includeProfile: true }
   * });
   * ```
   */
  debug(message: string, context?: LogContext): void {
    this.log('debug', { message, context });
  }

  /**
   * 记录信息日志
   * 
   * 功能描述：
   * 记录重要的业务操作和系统状态变更，用于业务监控和审计
   * 
   * 使用场景：
   * - 用户登录成功
   * - 重要业务操作完成
   * - 系统状态变更
   * - 关键流程节点记录
   * 
   * @param message 信息消息内容
   * @param context 操作上下文信息
   * 
   * @example
   * ```typescript
   * this.logger.info('用户登录成功', {
   *   module: 'AuthService',
   *   operation: 'userLogin',
   *   userId: 'user123',
   *   timestamp: new Date().toISOString()
   * });
   * ```
   */
  info(message: string, context?: LogContext): void {
    this.log('info', { message, context });
  }

  /**
   * 记录警告日志
   * 
   * 功能描述：
   * 记录需要关注但不影响正常业务流程的警告信息
   * 
   * 使用场景：
   * - 参数验证失败
   * - 权限检查失败
   * - 资源不存在
   * - 业务规则违反
   * - 性能指标异常
   * 
   * @param message 警告消息内容
   * @param context 警告上下文信息
   * 
   * @example
   * ```typescript
   * this.logger.warn('用户尝试访问不存在的资源', {
   *   module: 'ResourceService',
   *   operation: 'getResource',
   *   userId: 'user123',
   *   resourceId: 'res456',
   *   reason: 'resource_not_found'
   * });
   * ```
   */
  warn(message: string, context?: LogContext): void {
    this.log('warn', { message, context });
  }

  /**
   * 记录错误日志
   * 
   * 功能描述：
   * 记录影响业务功能正常使用的错误信息，包含详细的错误上下文和堆栈信息
   * 
   * 使用场景：
   * - 业务逻辑异常
   * - 数据库操作失败
   * - 第三方服务调用失败
   * - 系统内部错误
   * 
   * @param message 错误消息内容
   * @param context 错误上下文信息
   * @param stack 错误堆栈信息，用于问题定位
   * 
   * @example
   * ```typescript
   * this.logger.error('数据库连接失败', {
   *   module: 'DatabaseService',
   *   operation: 'connect',
   *   error: error.message,
   *   timestamp: new Date().toISOString()
   * }, error.stack);
   * ```
   */
  error(message: string, context?: LogContext, stack?: string): void {
    this.log('error', { message, context, stack });
  }

  /**
   * 记录致命错误日志
   * 
   * 功能描述：
   * 记录可能导致系统不可用的严重错误，需要立即处理
   * 
   * 使用场景：
   * - 数据库完全不可用
   * - 关键服务宕机
   * - 系统资源耗尽
   * - 安全漏洞被利用
   * 
   * @param message 致命错误消息内容
   * @param context 错误上下文信息
   * @param stack 错误堆栈信息
   * 
   * @example
   * ```typescript
   * this.logger.fatal('数据库连接池耗尽', {
   *   module: 'DatabaseService',
   *   operation: 'getConnection',
   *   activeConnections: 100,
   *   maxConnections: 100,
   *   timestamp: new Date().toISOString()
   * }, error.stack);
   * ```
   */
  fatal(message: string, context?: LogContext, stack?: string): void {
    this.log('fatal', { message, context, stack });
  }

  /**
   * 记录追踪日志
   * 
   * 功能描述：
   * 记录极细粒度的执行追踪信息，用于深度调试和性能分析
   * 
   * 使用场景：
   * - 循环内的变量状态
   * - 算法执行步骤
   * - 性能关键路径追踪
   * - 复杂业务逻辑的详细执行流程
   * 
   * 注意事项：
   * - 仅在开发环境启用
   * - 会产生大量日志，谨慎使用
   * 
   * @param message 追踪消息内容
   * @param context 追踪上下文信息
   * 
   * @example
   * ```typescript
   * this.logger.trace('处理数组元素', {
   *   module: 'DataProcessor',
   *   operation: 'processArray',
   *   currentIndex: i,
   *   elementValue: array[i],
   *   totalElements: array.length
   * });
   * ```
   */
  trace(message: string, context?: LogContext): void {
    this.log('trace', { message, context });
  }

  // ========== 便捷方法 ==========
  
  /**
   * 绑定请求上下文的日志记录器
   * 
   * 功能描述：
   * 创建一个绑定了特定请求上下文的日志记录器，自动携带请求相关信息
   * 
   * 业务逻辑：
   * 1. 从请求对象中提取关键信息
   * 2. 构建基础上下文对象
   * 3. 返回包装后的日志方法集合
   * 4. 每次调用时自动合并基础上下文和额外上下文
   * 
   * 使用场景：
   * - HTTP 请求处理过程中的日志记录
   * - WebSocket 连接的日志追踪
   * - 需要关联用户行为的业务操作
   * 
   * @param req HTTP 请求对象或类似的上下文对象
   * @param module 模块名称，标识日志来源
   * @returns 绑定了请求上下文的日志方法对象
   * 
   * @example
   * ```typescript
   * // 在 Controller 中使用
   * const requestLogger = this.logger.bindRequest(req, 'UserController');
   * requestLogger.info('开始处理用户请求', { action: 'getUserProfile' });
   * requestLogger.error('处理失败', error.stack, { reason: 'database_error' });
   * ```
   */
  bindRequest(req: any, module: string) {
    const baseContext: LogContext = {
      reqId: req.id || req.headers['x-request-id'],
      userId: req.headers['x-user-id'] || 'anonymous',
      ip: req.ip,
      module,
    };

    return {
      debug: (message: string, extra?: LogContext) => this.debug(message, { ...baseContext, ...extra }),
      info: (message: string, extra?: LogContext) => this.info(message, { ...baseContext, ...extra }),
      warn: (message: string, extra?: LogContext) => this.warn(message, { ...baseContext, ...extra }),
      error: (message: string, stack?: string, extra?: LogContext) => this.error(message, { ...baseContext, ...extra }, stack),
      fatal: (message: string, stack?: string, extra?: LogContext) => this.fatal(message, { ...baseContext, ...extra }, stack),
      trace: (message: string, extra?: LogContext) => this.trace(message, { ...baseContext, ...extra }),
    };
  }
}