import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import { Observable } from 'rxjs';
import { Request } from 'express';
import { Reflector } from '@nestjs/core';
import { LogsService } from '../../logs/logs.service';
import { IS_PUBLIC_KEY } from '../../auth/decorators/public.decorator';

@Injectable()
export class LoggingInterceptor implements NestInterceptor {
  constructor(
    private logsService: LogsService,
    private reflector: Reflector,
  ) {}

  intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
    const request = context.switchToHttp().getRequest<Request>();
    const { method, url, ip, headers } = request;
    const userAgent = headers['user-agent'] || '';

    // 检查是否为公共接口，公共接口不记录日志
    const isPublic = this.reflector.getAllAndOverride<boolean>(IS_PUBLIC_KEY, [
      context.getHandler(),
      context.getClass(),
    ]);

    // 跳过日志接口本身，避免循环记录
    if (url.startsWith('/logs') || isPublic) {
      return next.handle();
    }

    // 获取用户信息（如果已认证）
    const user = (request as any).user;
    const userId = user?.userId || null;

    // 构建操作内容
    const action = `${method} ${url}`;
    const contentData = {
      method,
      url,
      query: request.query,
      body: this.sanitizeBody(request.body),
    };
    // 限制内容长度，避免过长（TEXT 类型最大 65KB，这里限制为 50KB）
    console.log('[LoggingInterceptor]', contentData);
    const content = this.truncateContent(JSON.stringify(contentData), 50000);

    // 异步记录日志，不阻塞请求
    this.logsService
      .create({
        userId,
        action,
        content,
        ip: ip || request.ip || '',
        userAgent,
      })
      .catch((error) => {
        // 日志记录失败不影响主流程，只打印错误
        console.error('Failed to log request:', error);
      });

    return next.handle();
  }

  // 清理敏感信息（如密码）
  private sanitizeBody(body: any): any {
    if (!body || typeof body !== 'object') {
      return body;
    }

    const sanitized = { ...body };
    const sensitiveFields = ['password', 'oldPassword', 'newPassword', 'token'];

    sensitiveFields.forEach((field) => {
      if (sanitized[field]) {
        sanitized[field] = '***';
      }
    });

    return sanitized;
  }

  // 截断内容，避免超过数据库字段限制
  private truncateContent(content: string, maxLength: number): string {
    if (!content || content.length <= maxLength) {
      return content;
    }
    return content.substring(0, maxLength - 50) + '\n...(内容过长，已截断)';
  }
}
