/**
 * 管理员操作日志拦截器
 * 
 * 功能描述：
 * - 自动拦截管理员操作并记录日志
 * - 记录操作前后的数据状态
 * - 监控操作性能和错误
 * - 支持敏感操作的特殊处理
 * 
 * 职责分离：
 * - 操作拦截：拦截控制器方法的执行
 * - 数据捕获：记录请求参数和响应数据
 * - 日志记录：调用日志服务记录操作
 * - 错误处理：记录操作异常信息
 * 
 * 最近修改：
 * - 2026-01-08: 注释规范优化 - 修正@author字段，更新版本号和修改记录 (修改者: moyin)
 * - 2026-01-08: 功能新增 - 创建管理员操作日志拦截器 (修改者: assistant)
 * 
 * @author moyin
 * @version 1.0.1
 * @since 2026-01-08
 * @lastModified 2026-01-08
 */

import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
  Logger,
} from '@nestjs/common';
import { Reflector } from '@nestjs/core';
import { Observable, throwError } from 'rxjs';
import { tap, catchError } from 'rxjs/operators';
import { AdminOperationLogService } from './admin_operation_log.service';
import { LOG_ADMIN_OPERATION_KEY, LogAdminOperationOptions } from './log_admin_operation.decorator';
import { SENSITIVE_FIELDS, OPERATION_RESULTS } from './admin_constants';
import { extractClientIp, generateRequestId, sanitizeRequestBody } from './admin_utils';

@Injectable()
export class AdminOperationLogInterceptor implements NestInterceptor {
  private readonly logger = new Logger(AdminOperationLogInterceptor.name);

  constructor(
    private readonly reflector: Reflector,
    private readonly logService: AdminOperationLogService,
  ) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const logOptions = this.reflector.get<LogAdminOperationOptions>(
      LOG_ADMIN_OPERATION_KEY,
      context.getHandler(),
    );

    // 如果没有日志配置，直接执行
    if (!logOptions) {
      return next.handle();
    }

    const request = context.switchToHttp().getRequest();
    const response = context.switchToHttp().getResponse();
    const startTime = Date.now();

    // 提取请求信息
    const adminUser = request.user;
    const clientIp = extractClientIp(request);
    const userAgent = request.headers['user-agent'] || 'unknown';
    const httpMethodPath = `${request.method} ${request.route?.path || request.url}`;
    const requestId = generateRequestId();

    // 提取请求参数
    const requestParams = logOptions.captureRequestParams !== false ? {
      params: request.params,
      query: request.query,
      body: sanitizeRequestBody(request.body)
    } : undefined;

    // 提取目标ID（如果存在）
    const targetId = request.params?.id || request.body?.id || request.query?.id;

    let beforeData: any = undefined;
    let operationError: any = null;

    return next.handle().pipe(
      tap((responseData) => {
        // 操作成功，记录日志
        this.recordLog({
          logOptions,
          adminUser,
          clientIp,
          userAgent,
          httpMethodPath,
          requestId,
          requestParams,
          targetId,
          beforeData,
          afterData: logOptions.captureAfterData !== false ? responseData : undefined,
          operationResult: OPERATION_RESULTS.SUCCESS,
          durationMs: Date.now() - startTime,
          affectedRecords: this.extractAffectedRecords(responseData),
        });
      }),
      catchError((error) => {
        // 操作失败，记录错误日志
        operationError = error;
        this.recordLog({
          logOptions,
          adminUser,
          clientIp,
          userAgent,
          httpMethodPath,
          requestId,
          requestParams,
          targetId,
          beforeData,
          operationResult: OPERATION_RESULTS.FAILED,
          errorMessage: error.message || String(error),
          errorCode: error.code || error.status || 'UNKNOWN_ERROR',
          durationMs: Date.now() - startTime,
        });

        return throwError(() => error);
      }),
    );
  }

  /**
   * 记录操作日志
   */
  private async recordLog(params: {
    logOptions: LogAdminOperationOptions;
    adminUser: any;
    clientIp: string;
    userAgent: string;
    httpMethodPath: string;
    requestId: string;
    requestParams?: any;
    targetId?: string;
    beforeData?: any;
    afterData?: any;
    operationResult: keyof typeof OPERATION_RESULTS;
    errorMessage?: string;
    errorCode?: string;
    durationMs: number;
    affectedRecords?: number;
  }) {
    try {
      await this.logService.createLog({
        adminUserId: params.adminUser?.id || 'unknown',
        adminUsername: params.adminUser?.username || 'unknown',
        operationType: params.logOptions.operationType,
        targetType: params.logOptions.targetType,
        targetId: params.targetId,
        operationDescription: params.logOptions.description,
        httpMethodPath: params.httpMethodPath,
        requestParams: params.requestParams,
        beforeData: params.beforeData,
        afterData: params.afterData,
        operationResult: params.operationResult,
        errorMessage: params.errorMessage,
        errorCode: params.errorCode,
        durationMs: params.durationMs,
        clientIp: params.clientIp,
        userAgent: params.userAgent,
        requestId: params.requestId,
        isSensitive: params.logOptions.isSensitive || false,
        affectedRecords: params.affectedRecords || 0,
      });
    } catch (error) {
      this.logger.error('记录操作日志失败', {
        error: error instanceof Error ? error.message : String(error),
        adminUserId: params.adminUser?.id,
        operationType: params.logOptions.operationType,
        targetType: params.logOptions.targetType,
      });
    }
  }

  /**
   * 提取影响的记录数量
   */
  private extractAffectedRecords(responseData: any): number {
    if (!responseData || typeof responseData !== 'object') {
      return 0;
    }

    // 从响应数据中提取影响的记录数
    if (responseData.data) {
      if (Array.isArray(responseData.data.items)) {
        return responseData.data.items.length;
      }
      if (responseData.data.total !== undefined) {
        return responseData.data.total;
      }
      if (responseData.data.success !== undefined && responseData.data.failed !== undefined) {
        return responseData.data.success + responseData.data.failed;
      }
    }

    return 1; // 默认为1条记录
  }
}