import {
  Controller,
  Post,
  Get,
  Query,
  Body,
  HttpCode,
  HttpStatus,
  UseGuards,
  Req,
  Ip,
} from '@nestjs/common';
import { ApiTags, ApiOperation, ApiResponse, ApiBearerAuth } from '@nestjs/swagger';
import { AuthGuard } from '@nestjs/passport';
import { ThrottlerGuard } from '@nestjs/throttler';
import { AuthService } from '../../../application/services/auth.service';
import { WechatService } from '../../../application/services/wechat.service';
import { AlipayService } from '../../../application/services/alipay.service';
import { AlipayProvider } from '../../../infrastructure/alipay/alipay.provider';
import { GoogleService } from '../../../application/services/google.service';
import { AppleService } from '../../../application/services/apple.service';
import { RegisterDto } from '../dto/register.dto';
import { LoginDto } from '../dto/login.dto';
import { RefreshTokenDto } from '../dto/refresh-token.dto';
import { ChangePasswordDto } from '../dto/change-password.dto';
import { SendSmsCodeDto } from '../dto/send-sms-code.dto';
import { LoginPhoneDto } from '../dto/login-phone.dto';
import { ResetPasswordDto } from '../dto/reset-password.dto';
import { ChangePhoneDto } from '../dto/change-phone.dto';
import { SendEmailCodeDto } from '../dto/send-email-code.dto';
import { RegisterEmailDto } from '../dto/register-email.dto';
import { LoginEmailDto } from '../dto/login-email.dto';
import { ResetPasswordEmailDto } from '../dto/reset-password-email.dto';
import { WechatLoginDto } from '../dto/wechat-login.dto';
import { AlipayLoginDto } from '../dto/alipay-login.dto';
import { GoogleLoginDto } from '../dto/google-login.dto';
import { AppleLoginDto } from '../dto/apple-login.dto';

@ApiTags('Auth')
@Controller('auth')
export class AuthController {
  constructor(
    private readonly authService: AuthService,
    private readonly wechatService: WechatService,
    private readonly alipayService: AlipayService,
    private readonly googleService: GoogleService,
    private readonly appleService: AppleService,
    private readonly alipayProvider: AlipayProvider,
  ) {}

  /* ── SMS 验证码 ── */

  @Post('sms/send')
  @HttpCode(HttpStatus.OK)
  @UseGuards(ThrottlerGuard)
  @ApiOperation({ summary: '发送短信验证码' })
  @ApiResponse({ status: 200, description: '验证码发送成功' })
  @ApiResponse({ status: 400, description: '手机号无效 / 日发送限额已满' })
  async sendSmsCode(@Body() dto: SendSmsCodeDto) {
    const result = await this.authService.sendSmsCode(dto.phone, dto.type);
    return {
      code: 0,
      data: result,
      message: '验证码发送成功',
    };
  }

  /* ── 注册 ── */

  @Post('register')
  @ApiOperation({ summary: '手机号注册 (需先获取验证码)' })
  @ApiResponse({ status: 201, description: '注册成功' })
  @ApiResponse({ status: 400, description: '验证码错误' })
  @ApiResponse({ status: 409, description: '手机号已注册' })
  async register(@Body() dto: RegisterDto) {
    const result = await this.authService.register(dto);
    return {
      code: 0,
      data: result,
      message: '注册成功',
    };
  }

  /* ── 密码登录 ── */

  @Post('login')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '密码登录 (手机号/邮箱 + 密码)' })
  @ApiResponse({ status: 200, description: '登录成功' })
  @ApiResponse({ status: 401, description: '账号或密码错误' })
  @ApiResponse({ status: 403, description: '账号已锁定/冻结' })
  async login(@Body() dto: LoginDto, @Ip() ip: string) {
    const result = await this.authService.login({
      ...dto,
      ipAddress: ip,
    });
    return {
      code: 0,
      data: result,
      message: '登录成功',
    };
  }

  /* ── 短信验证码登录 ── */

  @Post('login-phone')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '短信验证码登录' })
  @ApiResponse({ status: 200, description: '登录成功' })
  @ApiResponse({ status: 401, description: '验证码错误或手机号未注册' })
  async loginWithPhone(@Body() dto: LoginPhoneDto, @Ip() ip: string) {
    const result = await this.authService.loginWithPhone(
      dto.phone,
      dto.smsCode,
      dto.deviceInfo,
      ip,
    );
    return {
      code: 0,
      data: result,
      message: '登录成功',
    };
  }

  /* ── 重置密码 ── */

  @Post('reset-password')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '重置密码 (手机号 + 验证码 + 新密码)' })
  @ApiResponse({ status: 200, description: '密码重置成功' })
  @ApiResponse({ status: 400, description: '验证码错误或手机号未注册' })
  async resetPassword(@Body() dto: ResetPasswordDto) {
    await this.authService.resetPassword(dto.phone, dto.smsCode, dto.newPassword);
    return {
      code: 0,
      data: null,
      message: '密码重置成功，请重新登录',
    };
  }

  /* ── 更换手机号 ── */

  @Post('change-phone')
  @HttpCode(HttpStatus.OK)
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: '更换绑定手机号 (需登录)' })
  @ApiResponse({ status: 200, description: '手机号更换成功' })
  @ApiResponse({ status: 400, description: '验证码错误' })
  @ApiResponse({ status: 409, description: '新手机号已被使用' })
  async changePhone(@Req() req: any, @Body() dto: ChangePhoneDto) {
    await this.authService.changePhone(req.user.id, dto.newPhone, dto.newSmsCode);
    return {
      code: 0,
      data: null,
      message: '手机号更换成功',
    };
  }

  /* ── Token 刷新 ── */

  @Post('refresh')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '刷新 access token' })
  @ApiResponse({ status: 200, description: 'Token 刷新成功' })
  @ApiResponse({ status: 401, description: 'Refresh token 无效' })
  async refresh(@Body() dto: RefreshTokenDto) {
    const tokens = await this.authService.refreshToken(dto.refreshToken);
    return {
      code: 0,
      data: tokens,
      message: 'Token 刷新成功',
    };
  }

  /* ── 登出 ── */

  @Post('logout')
  @HttpCode(HttpStatus.OK)
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: '登出 (撤销所有 refresh token)' })
  async logout(@Req() req: any) {
    await this.authService.logout(req.user.id);
    return {
      code: 0,
      data: null,
      message: '已登出',
    };
  }

  /* ── 修改密码 ── */

  @Post('change-password')
  @HttpCode(HttpStatus.OK)
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiOperation({ summary: '修改密码 (需登录)' })
  async changePassword(@Req() req: any, @Body() dto: ChangePasswordDto) {
    await this.authService.changePassword(req.user.id, dto.oldPassword, dto.newPassword);
    return {
      code: 0,
      data: null,
      message: '密码修改成功',
    };
  }

  /* ── 邮件验证码 ── */

  @Post('email/send')
  @HttpCode(HttpStatus.OK)
  @UseGuards(ThrottlerGuard)
  @ApiOperation({ summary: '发送邮件验证码' })
  @ApiResponse({ status: 200, description: '验证码发送成功' })
  @ApiResponse({ status: 400, description: '邮箱格式无效 / 日发送限额已满' })
  async sendEmailCode(@Body() dto: SendEmailCodeDto) {
    const result = await this.authService.sendEmailCode(dto.email, dto.type);
    return {
      code: 0,
      data: result,
      message: '验证码已发送',
    };
  }

  /* ── 邮箱注册 ── */

  @Post('register-email')
  @ApiOperation({ summary: '邮箱注册 (需先获取邮件验证码)' })
  @ApiResponse({ status: 201, description: '注册成功' })
  @ApiResponse({ status: 400, description: '验证码错误' })
  @ApiResponse({ status: 409, description: '邮箱已注册' })
  async registerByEmail(@Body() dto: RegisterEmailDto) {
    const result = await this.authService.registerByEmail(dto);
    return {
      code: 0,
      data: result,
      message: '注册成功',
    };
  }

  /* ── 邮件验证码登录 ── */

  @Post('login-email')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '邮件验证码登录 (无需密码)' })
  @ApiResponse({ status: 200, description: '登录成功' })
  @ApiResponse({ status: 401, description: '验证码错误或邮箱未注册' })
  async loginWithEmail(@Body() dto: LoginEmailDto, @Ip() ip: string) {
    const result = await this.authService.loginWithEmail(
      dto.email,
      dto.emailCode,
      dto.deviceInfo,
      ip,
    );
    return {
      code: 0,
      data: result,
      message: '登录成功',
    };
  }

  /* ── 邮件重置密码 ── */

  @Post('reset-password-email')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '通过邮件验证码重置密码' })
  @ApiResponse({ status: 200, description: '密码重置成功' })
  @ApiResponse({ status: 400, description: '验证码错误或邮箱未注册' })
  async resetPasswordByEmail(@Body() dto: ResetPasswordEmailDto) {
    await this.authService.resetPasswordByEmail(dto.email, dto.emailCode, dto.newPassword);
    return {
      code: 0,
      data: null,
      message: '密码重置成功，请重新登录',
    };
  }

  /* ── 支付宝登录 / 注册 ── */

  /**
   * 生成支付宝移动端授权字符串（供 tobias 3.x+ 使用）
   *
   * tobias 3.x 后 `Tobias().auth(authString)` 需要由服务端提供已签名的 authString，
   * 不再允许客户端直接传 appId+scope（安全升级，防止私钥泄露到客户端）。
   *
   * 流程：
   *   Flutter → GET /auth/alipay/auth-string
   *          → Tobias().auth(authString) → 拉起支付宝 App
   *          → 用户授权 → 支付宝回传 auth_code
   *          → POST /auth/alipay (现有接口)
   */
  @Get('alipay/auth-string')
  @ApiOperation({ summary: '获取支付宝移动端签名授权字符串（tobias 3.x+）' })
  @ApiResponse({ status: 200, description: '返回签名后的 authString' })
  getAlipayAuthString(@Query('scope') scope?: string) {
    const authString = this.alipayProvider.generateMobileAuthString(
      scope || 'auth_user',
    );
    return { code: 0, data: { authString }, message: 'ok' };
  }

  @Post('alipay')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '支付宝一键登录（新用户自动注册）' })
  @ApiResponse({ status: 200, description: '登录成功，返回 JWT' })
  @ApiResponse({ status: 400, description: '支付宝 auth_code 无效或已过期' })
  async alipayLogin(@Body() dto: AlipayLoginDto, @Ip() ip: string) {
    const result = await this.alipayService.loginOrRegister(
      dto.authCode,
      dto.referralCode,
      dto.deviceInfo,
      ip,
    );
    return { code: 0, data: result, message: '登录成功' };
  }

  /* ── Google 登录 / 注册 ── */

  @Post('google')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Google 一键登录（新用户自动注册）' })
  @ApiResponse({ status: 200, description: '登录成功，返回 JWT' })
  @ApiResponse({ status: 401, description: 'Google ID Token 无效' })
  async googleLogin(@Body() dto: GoogleLoginDto, @Ip() ip: string) {
    const result = await this.googleService.loginOrRegister(
      dto.idToken,
      dto.referralCode,
      dto.deviceInfo,
      ip,
    );
    return { code: 0, data: result, message: '登录成功' };
  }

  /* ── Apple 登录 / 注册 ── */

  @Post('apple')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: 'Apple 一键登录（仅 iOS，新用户自动注册）' })
  @ApiResponse({ status: 200, description: '登录成功，返回 JWT' })
  @ApiResponse({ status: 401, description: 'Apple Identity Token 无效' })
  async appleLogin(@Body() dto: AppleLoginDto, @Ip() ip: string) {
    const result = await this.appleService.loginOrRegister(
      dto.identityToken,
      dto.displayName,
      dto.referralCode,
      dto.deviceInfo,
      ip,
    );
    return { code: 0, data: result, message: '登录成功' };
  }

  /* ── 微信登录 / 注册 ── */

  @Post('wechat')
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: '微信一键登录（新用户自动注册）' })
  @ApiResponse({ status: 200, description: '登录成功，返回 JWT' })
  @ApiResponse({ status: 400, description: '微信 code 无效或已过期' })
  async wechatLogin(@Body() dto: WechatLoginDto, @Ip() ip: string) {
    const result = await this.wechatService.loginOrRegister(
      dto.code,
      dto.referralCode,
      dto.deviceInfo,
      ip,
    );
    return {
      code: 0,
      data: result,
      message: '登录成功',
    };
  }
}
