/**
 * 登录网关控制器
 *
 * 架构层级：Gateway Layer（网关层）
 *
 * 功能描述：
 * - 处理登录相关的HTTP请求和响应
 * - 提供RESTful API接口
 * - 数据验证和格式化
 * - 协议处理和错误响应
 *
 * 职责分离：
 * - 专注于HTTP协议处理和请求响应
 * - 调用业务层服务完成具体功能
 * - 处理API文档和参数验证
 * - 不包含业务逻辑，只做数据转换和路由
 *
 * 依赖关系：
 * - 依赖 Business Layer 的 LoginService
 * - 使用 DTO 进行数据验证
 * - 使用 Guard 进行认证保护
 *
 * API端点：
 * - POST /auth/login - 用户登录
 * - POST /auth/github - GitHub OAuth登录
 * - POST /auth/forgot-password - 发送密码重置验证码
 * - POST /auth/reset-password - 重置密码
 * - PUT /auth/change-password - 修改密码
 * - POST /auth/refresh-token - 刷新访问令牌
 * - POST /auth/verification-code-login - 验证码登录
 * - POST /auth/send-login-verification-code - 发送登录验证码
 *
 * @author moyin
 * @version 2.0.0
 * @since 2026-01-14
 * @lastModified 2026-01-14
 */

import {
  Controller,
  Post,
  Put,
  Body,
  HttpCode,
  HttpStatus,
  ValidationPipe,
  UsePipes,
  Logger,
  Res
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiResponse as SwaggerApiResponse,
  ApiBody
} from '@nestjs/swagger';
import { Response } from 'express';
import { LoginService } from '../../business/auth/login.service';
import {
  LoginDto,
  GitHubOAuthDto,
  ForgotPasswordDto,
  ResetPasswordDto,
  ChangePasswordDto,
  VerificationCodeLoginDto,
  SendLoginVerificationCodeDto,
  RefreshTokenDto,
  SendEmailVerificationDto
} from './dto/login.dto';
import {
  LoginResponseDto,
  GitHubOAuthResponseDto,
  ForgotPasswordResponseDto,
  CommonResponseDto,
  RefreshTokenResponseDto
} from './dto/login_response.dto';
import { Throttle, ThrottlePresets } from '../../core/security_core/throttle.decorator';
import { Timeout, TimeoutPresets } from '../../core/security_core/timeout.decorator';

// 错误代码到HTTP状态码的映射
const ERROR_STATUS_MAP = {
  LOGIN_FAILED: HttpStatus.UNAUTHORIZED,
  TEST_MODE_ONLY: HttpStatus.PARTIAL_CONTENT,
  TOKEN_REFRESH_FAILED: HttpStatus.UNAUTHORIZED,
  GITHUB_OAUTH_FAILED: HttpStatus.UNAUTHORIZED,
  SEND_CODE_FAILED: HttpStatus.BAD_REQUEST,
  RESET_PASSWORD_FAILED: HttpStatus.BAD_REQUEST,
  CHANGE_PASSWORD_FAILED: HttpStatus.BAD_REQUEST,
  VERIFICATION_CODE_LOGIN_FAILED: HttpStatus.UNAUTHORIZED,
  INVALID_VERIFICATION_CODE: HttpStatus.BAD_REQUEST,
} as const;

@ApiTags('auth')
@Controller('auth')
export class LoginController {
  private readonly logger = new Logger(LoginController.name);

  constructor(private readonly loginService: LoginService) {}

  /**
   * 通用响应处理方法
   *
   * 职责：
   * - 根据业务结果设置HTTP状态码
   * - 处理不同类型的错误响应
   * - 统一响应格式和错误处理
   *
   * @param result 业务服务返回的结果
   * @param res Express响应对象
   * @param successStatus 成功时的HTTP状态码，默认为200
   * @private
   */
  private handleResponse(result: any, res: Response, successStatus: HttpStatus = HttpStatus.OK): void {
    if (result.success) {
      res.status(successStatus).json(result);
      return;
    }

    const statusCode = this.getErrorStatusCode(result);
    res.status(statusCode).json(result);
  }

  /**
   * 根据错误代码和消息获取HTTP状态码
   *
   * @param result 业务服务返回的结果
   * @returns HTTP状态码
   * @private
   */
  private getErrorStatusCode(result: any): HttpStatus {
    if (result.error_code && ERROR_STATUS_MAP[result.error_code as keyof typeof ERROR_STATUS_MAP]) {
      return ERROR_STATUS_MAP[result.error_code as keyof typeof ERROR_STATUS_MAP];
    }

    if (result.message?.includes('已存在') || result.message?.includes('已被注册')) {
      return HttpStatus.CONFLICT;
    }

    if (result.message?.includes('令牌验证失败') || result.message?.includes('已过期')) {
      return HttpStatus.UNAUTHORIZED;
    }

    if (result.message?.includes('用户不存在')) {
      return HttpStatus.NOT_FOUND;
    }

    return HttpStatus.BAD_REQUEST;
  }

  /**
   * 用户登录
   *
   * @param loginDto 登录数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '用户登录',
    description: '支持用户名、邮箱或手机号登录'
  })
  @ApiBody({ type: LoginDto })
  @SwaggerApiResponse({
    status: 200,
    description: '登录成功',
    type: LoginResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误'
  })
  @SwaggerApiResponse({
    status: 401,
    description: '用户名或密码错误'
  })
  @SwaggerApiResponse({
    status: 403,
    description: '账户被禁用或锁定'
  })
  @SwaggerApiResponse({
    status: 429,
    description: '登录尝试过于频繁'
  })
  @Throttle(ThrottlePresets.LOGIN_PER_ACCOUNT)
  @Timeout(TimeoutPresets.NORMAL)
  @Post('login')
  @UsePipes(new ValidationPipe({ transform: true }))
  async login(@Body() loginDto: LoginDto, @Res() res: Response): Promise<void> {
    const result = await this.loginService.login({
      identifier: loginDto.identifier,
      password: loginDto.password
    });

    this.handleResponse(result, res);
  }

  /**
   * GitHub OAuth登录
   *
   * @param githubDto GitHub OAuth数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: 'GitHub OAuth登录',
    description: '使用GitHub账户登录或注册'
  })
  @ApiBody({ type: GitHubOAuthDto })
  @SwaggerApiResponse({
    status: 200,
    description: 'GitHub登录成功',
    type: GitHubOAuthResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误'
  })
  @SwaggerApiResponse({
    status: 401,
    description: 'GitHub认证失败'
  })
  @Post('github')
  @UsePipes(new ValidationPipe({ transform: true }))
  async githubOAuth(@Body() githubDto: GitHubOAuthDto, @Res() res: Response): Promise<void> {
    const result = await this.loginService.githubOAuth({
      github_id: githubDto.github_id,
      username: githubDto.username,
      nickname: githubDto.nickname,
      email: githubDto.email,
      avatar_url: githubDto.avatar_url
    });

    this.handleResponse(result, res);
  }

  /**
   * 发送密码重置验证码
   *
   * @param forgotPasswordDto 忘记密码数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '发送密码重置验证码',
    description: '向用户邮箱或手机发送密码重置验证码'
  })
  @ApiBody({ type: ForgotPasswordDto })
  @SwaggerApiResponse({
    status: 200,
    description: '验证码发送成功',
    type: ForgotPasswordResponseDto
  })
  @SwaggerApiResponse({
    status: 206,
    description: '测试模式：验证码已生成但未真实发送',
    type: ForgotPasswordResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误'
  })
  @SwaggerApiResponse({
    status: 404,
    description: '用户不存在'
  })
  @SwaggerApiResponse({
    status: 429,
    description: '发送频率过高'
  })
  @Throttle(ThrottlePresets.SEND_CODE)
  @Post('forgot-password')
  @UsePipes(new ValidationPipe({ transform: true }))
  async forgotPassword(
    @Body() forgotPasswordDto: ForgotPasswordDto,
    @Res() res: Response
  ): Promise<void> {
    const result = await this.loginService.sendPasswordResetCode(forgotPasswordDto.identifier);
    this.handleResponse(result, res);
  }

  /**
   * 重置密码
   *
   * @param resetPasswordDto 重置密码数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '重置密码',
    description: '使用验证码重置用户密码'
  })
  @ApiBody({ type: ResetPasswordDto })
  @SwaggerApiResponse({
    status: 200,
    description: '密码重置成功',
    type: CommonResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误或验证码无效'
  })
  @SwaggerApiResponse({
    status: 404,
    description: '用户不存在'
  })
  @SwaggerApiResponse({
    status: 429,
    description: '重置请求过于频繁'
  })
  @Throttle(ThrottlePresets.RESET_PASSWORD)
  @Post('reset-password')
  @UsePipes(new ValidationPipe({ transform: true }))
  async resetPassword(@Body() resetPasswordDto: ResetPasswordDto, @Res() res: Response): Promise<void> {
    const result = await this.loginService.resetPassword({
      identifier: resetPasswordDto.identifier,
      verificationCode: resetPasswordDto.verification_code,
      newPassword: resetPasswordDto.new_password
    });

    this.handleResponse(result, res);
  }

  /**
   * 修改密码
   *
   * @param changePasswordDto 修改密码数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '修改密码',
    description: '用户修改自己的密码（需要提供旧密码）'
  })
  @ApiBody({ type: ChangePasswordDto })
  @SwaggerApiResponse({
    status: 200,
    description: '密码修改成功',
    type: CommonResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误或旧密码不正确'
  })
  @SwaggerApiResponse({
    status: 404,
    description: '用户不存在'
  })
  @Put('change-password')
  @UsePipes(new ValidationPipe({ transform: true }))
  async changePassword(@Body() changePasswordDto: ChangePasswordDto, @Res() res: Response): Promise<void> {
    const userId = BigInt(changePasswordDto.user_id);

    const result = await this.loginService.changePassword(
      userId,
      changePasswordDto.old_password,
      changePasswordDto.new_password
    );

    this.handleResponse(result, res);
  }

  /**
   * 验证码登录
   *
   * @param verificationCodeLoginDto 验证码登录数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '验证码登录',
    description: '使用邮箱或手机号和验证码进行登录，无需密码'
  })
  @ApiBody({ type: VerificationCodeLoginDto })
  @SwaggerApiResponse({
    status: 200,
    description: '验证码登录成功',
    type: LoginResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误'
  })
  @SwaggerApiResponse({
    status: 401,
    description: '验证码错误或已过期'
  })
  @SwaggerApiResponse({
    status: 404,
    description: '用户不存在'
  })
  @Post('verification-code-login')
  @HttpCode(HttpStatus.OK)
  @UsePipes(new ValidationPipe({ transform: true }))
  async verificationCodeLogin(
    @Body() verificationCodeLoginDto: VerificationCodeLoginDto,
    @Res() res: Response
  ): Promise<void> {
    const result = await this.loginService.verificationCodeLogin({
      identifier: verificationCodeLoginDto.identifier,
      verificationCode: verificationCodeLoginDto.verification_code
    });

    this.handleResponse(result, res);
  }

  /**
   * 发送登录验证码
   *
   * @param sendLoginVerificationCodeDto 发送验证码数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '发送登录验证码',
    description: '向用户邮箱或手机发送登录验证码'
  })
  @ApiBody({ type: SendLoginVerificationCodeDto })
  @SwaggerApiResponse({
    status: 200,
    description: '验证码发送成功',
    type: ForgotPasswordResponseDto
  })
  @SwaggerApiResponse({
    status: 206,
    description: '测试模式：验证码已生成但未真实发送',
    type: ForgotPasswordResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误'
  })
  @SwaggerApiResponse({
    status: 404,
    description: '用户不存在'
  })
  @SwaggerApiResponse({
    status: 429,
    description: '发送频率过高'
  })
  @Post('send-login-verification-code')
  @UsePipes(new ValidationPipe({ transform: true }))
  async sendLoginVerificationCode(
    @Body() sendLoginVerificationCodeDto: SendLoginVerificationCodeDto,
    @Res() res: Response
  ): Promise<void> {
    const result = await this.loginService.sendLoginVerificationCode(sendLoginVerificationCodeDto.identifier);
    this.handleResponse(result, res);
  }

  /**
   * 刷新访问令牌
   *
   * @param refreshTokenDto 刷新令牌数据
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '刷新访问令牌',
    description: '使用有效的刷新令牌生成新的访问令牌'
  })
  @ApiBody({ type: RefreshTokenDto })
  @SwaggerApiResponse({
    status: 200,
    description: '令牌刷新成功',
    type: RefreshTokenResponseDto
  })
  @SwaggerApiResponse({
    status: 400,
    description: '请求参数错误'
  })
  @SwaggerApiResponse({
    status: 401,
    description: '刷新令牌无效或已过期'
  })
  @SwaggerApiResponse({
    status: 404,
    description: '用户不存在或已被禁用'
  })
  @SwaggerApiResponse({
    status: 429,
    description: '刷新请求过于频繁'
  })
  @Throttle(ThrottlePresets.REFRESH_TOKEN)
  @Timeout(TimeoutPresets.NORMAL)
  @Post('refresh-token')
  @UsePipes(new ValidationPipe({ transform: true }))
  async refreshToken(@Body() refreshTokenDto: RefreshTokenDto, @Res() res: Response): Promise<void> {
    const result = await this.loginService.refreshAccessToken(refreshTokenDto.refresh_token);
    this.handleResponse(result, res);
  }

  /**
   * 调试验证码信息（仅开发环境）
   *
   * @param sendEmailVerificationDto 邮箱信息
   * @param res Express响应对象
   */
  @ApiOperation({
    summary: '调试验证码信息',
    description: '获取验证码的详细调试信息（仅开发环境）'
  })
  @ApiBody({ type: SendEmailVerificationDto })
  @Post('debug-verification-code')
  @UsePipes(new ValidationPipe({ transform: true }))
  async debugVerificationCode(
    @Body() sendEmailVerificationDto: SendEmailVerificationDto,
    @Res() res: Response
  ): Promise<void> {
    const result = await this.loginService.debugVerificationCode(sendEmailVerificationDto.email);
    res.status(HttpStatus.OK).json(result);
  }
}
