/**
 * JWT 认证守卫
 *
 * 功能描述：
 * - 验证请求中的 JWT 令牌
 * - 提取用户信息并添加到请求上下文
 * - 保护需要认证的路由
 *
 * 职责分离：
 * - 专注于JWT令牌验证和用户认证
 * - 提供统一的认证守卫机制
 * - 处理认证失败的异常情况
 *
 * 最近修改：
 * - 2026-01-07: 代码规范优化 - 文件夹扁平化，移除单文件文件夹结构
 * - 2026-01-07: 代码规范优化 - 文件重命名为snake_case格式，更新注释规范
 *
 * @author moyin
 * @version 1.0.2
 * @since 2025-01-05
 * @lastModified 2026-01-07
 */

import {
  Injectable,
  CanActivate,
  ExecutionContext,
  UnauthorizedException,
  Logger,
} from '@nestjs/common';
import { Request } from 'express';
import { LoginCoreService, JwtPayload } from '../../core/login_core/login_core.service';

/**
 * 扩展的请求接口，包含用户信息
 */
export interface AuthenticatedRequest extends Request {
  user: JwtPayload;
}

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

  constructor(private readonly loginCoreService: LoginCoreService) {}

  /**
   * JWT令牌验证和用户认证
   *
   * 业务逻辑：
   * 1. 从请求头中提取Bearer令牌
   * 2. 验证令牌的有效性和签名
   * 3. 解码令牌获取用户信息
   * 4. 将用户信息添加到请求上下文
   * 5. 记录认证成功或失败的日志
   * 6. 返回认证结果
   *
   * @param context 执行上下文，包含HTTP请求信息
   * @returns Promise<boolean> 认证是否成功
   * @throws UnauthorizedException 当令牌缺失或无效时
   *
   * @example
   * ```typescript
   * @Get('protected')
   * @UseGuards(JwtAuthGuard)
   * getProtectedData() {
   *   // 此方法需要有效的JWT令牌才能访问
   * }
   * ```
   */
  async canActivate(context: ExecutionContext): Promise<boolean> {
    const request = context.switchToHttp().getRequest<Request>();
    const token = this.extractTokenFromHeader(request);

    if (!token) {
      this.logger.warn('访问被拒绝：缺少认证令牌');
      throw new UnauthorizedException('缺少认证令牌');
    }

    try {
      // 使用Core层服务验证JWT令牌
      const payload = await this.loginCoreService.verifyToken(token, 'access');

      // 将用户信息添加到请求对象
      (request as AuthenticatedRequest).user = payload;

      this.logger.log(`用户认证成功: ${payload.username} (ID: ${payload.sub})`);
      return true;
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : '未知错误';
      this.logger.warn(`JWT 令牌验证失败: ${errorMessage}`);
      throw new UnauthorizedException('无效的认证令牌');
    }
  }

  /**
   * 从请求头中提取JWT令牌
   *
   * 业务逻辑：
   * 1. 获取Authorization请求头
   * 2. 解析Bearer令牌格式
   * 3. 验证令牌类型是否为Bearer
   * 4. 返回提取的令牌字符串
   *
   * @param request HTTP请求对象
   * @returns string | undefined JWT令牌字符串或undefined
   * @throws 无异常抛出，返回undefined表示令牌不存在
   *
   * @example
   * ```typescript
   * // 请求头格式：Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...
   * const token = this.extractTokenFromHeader(request);
   * ```
   */
  private extractTokenFromHeader(request: Request): string | undefined {
    const [type, token] = request.headers.authorization?.split(' ') ?? [];
    return type === 'Bearer' ? token : undefined;
  }
}