import {
  Controller,
  Post,
  Get,
  Put,
  Body,
  Param,
  Query,
  UseGuards,
  Headers,
  UseInterceptors,
  UploadedFile,
  BadRequestException,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiResponse,
  ApiConsumes,
  ApiBody,
  ApiQuery,
  ApiParam,
} from '@nestjs/swagger';
import { UserApplicationService } from '@/application/services/user-application.service';
import { StorageService } from '@/infrastructure/external/storage/storage.service';
import {
  JwtAuthGuard,
  Public,
  CurrentUser,
  CurrentUserData,
} from '@/shared/guards/jwt-auth.guard';
import {
  AutoCreateAccountCommand,
  RegisterByPhoneCommand,
  RegisterWithoutSmsVerifyCommand,
  RecoverByMnemonicCommand,
  RecoverByPhoneCommand,
  AutoLoginCommand,
  RegisterCommand,
  LoginCommand,
  BindPhoneNumberCommand,
  UpdateProfileCommand,
  SubmitKYCCommand,
  RemoveDeviceCommand,
  SendSmsCodeCommand,
  GetMyProfileQuery,
  GetMyDevicesQuery,
  GetUserByReferralCodeQuery,
  GetWalletStatusQuery,
  MarkMnemonicBackedUpCommand,
  VerifySmsCodeCommand,
  SetPasswordCommand,
  ChangePasswordCommand,
  SendEmailCodeCommand,
  BindEmailCommand,
  UnbindEmailCommand,
} from '@/application/commands';
import {
  AutoCreateAccountDto,
  RegisterByPhoneDto,
  RegisterWithoutSmsVerifyDto,
  RecoverByMnemonicDto,
  RecoverByPhoneDto,
  AutoLoginDto,
  SendSmsCodeDto,
  RegisterDto,
  LoginDto,
  BindPhoneDto,
  UpdateProfileDto,
  BindWalletDto,
  SubmitKYCDto,
  RemoveDeviceDto,
  RevokeMnemonicDto,
  FreezeAccountDto,
  UnfreezeAccountDto,
  RequestKeyRotationDto,
  GenerateBackupCodesDto,
  RecoverByBackupCodeDto,
  AutoCreateAccountResponseDto,
  RecoverAccountResponseDto,
  LoginResponseDto,
  UserProfileResponseDto,
  DeviceResponseDto,
  WalletStatusReadyResponseDto,
  WalletStatusGeneratingResponseDto,
  VerifySmsCodeDto,
  SetPasswordDto,
  ChangePasswordDto,
  LoginWithPasswordDto,
  ResetPasswordDto,
  SendEmailCodeDto,
  BindEmailDto,
  UnbindEmailDto,
  VerifyOldPhoneDto,
  SendNewPhoneCodeDto,
  ConfirmChangePhoneDto,
} from '@/api/dto';

@ApiTags('User')
@Controller('user')
@UseGuards(JwtAuthGuard)
export class UserAccountController {
  constructor(
    private readonly userService: UserApplicationService,
    private readonly storageService: StorageService,
  ) {}

  @Public()
  @Post('auto-create')
  @ApiOperation({ summary: '自动创建账户(首次打开APP)' })
  @ApiResponse({ status: 200, type: AutoCreateAccountResponseDto })
  async autoCreate(@Body() dto: AutoCreateAccountDto) {
    return this.userService.autoCreateAccount(
      new AutoCreateAccountCommand(
        dto.deviceId,
        dto.deviceName,
        dto.inviterReferralCode,
      ),
    );
  }

  @Public()
  @Post('register-by-phone')
  @ApiOperation({
    summary: '手机号注册(验证码+密码一步完成)',
    description: '验证短信验证码，创建账户，绑定手机号，设置密码，触发钱包生成',
  })
  @ApiResponse({ status: 200, type: AutoCreateAccountResponseDto })
  async registerByPhone(@Body() dto: RegisterByPhoneDto) {
    return this.userService.registerByPhone(
      new RegisterByPhoneCommand(
        dto.phoneNumber,
        dto.smsCode,
        dto.password,
        dto.deviceId,
        dto.deviceName,
        dto.inviterReferralCode,
      ),
    );
  }

  @Public()
  @Post('register-without-sms-verify')
  @ApiOperation({
    summary: '跳过短信验证注册',
    description:
      '用户收不到验证码时可以跳过验证继续注册，注册后 phoneVerified=false，需在 KYC 流程中完成验证',
  })
  @ApiResponse({ status: 200, type: AutoCreateAccountResponseDto })
  async registerWithoutSmsVerify(@Body() dto: RegisterWithoutSmsVerifyDto) {
    return this.userService.registerWithoutSmsVerify(
      new RegisterWithoutSmsVerifyCommand(
        dto.phoneNumber,
        dto.password,
        dto.deviceId,
        dto.deviceName,
        dto.inviterReferralCode,
      ),
    );
  }

  @Public()
  @Post('recover-by-mnemonic')
  @ApiOperation({ summary: '用序列号+助记词恢复账户' })
  @ApiResponse({ status: 200, type: RecoverAccountResponseDto })
  async recoverByMnemonic(@Body() dto: RecoverByMnemonicDto) {
    return this.userService.recoverByMnemonic(
      new RecoverByMnemonicCommand(
        dto.accountSequence,
        dto.mnemonic,
        dto.newDeviceId,
        dto.deviceName,
      ),
    );
  }

  @Public()
  @Post('recover-by-phone')
  @ApiOperation({ summary: '用序列号+手机号恢复账户' })
  @ApiResponse({ status: 200, type: RecoverAccountResponseDto })
  async recoverByPhone(@Body() dto: RecoverByPhoneDto) {
    return this.userService.recoverByPhone(
      new RecoverByPhoneCommand(
        dto.accountSequence,
        dto.phoneNumber,
        dto.smsCode,
        dto.newDeviceId,
        dto.deviceName,
      ),
    );
  }

  @Public()
  @Post('auto-login')
  @ApiOperation({ summary: '自动登录(Token刷新)' })
  @ApiResponse({ status: 200, type: LoginResponseDto })
  async autoLogin(@Body() dto: AutoLoginDto) {
    return this.userService.autoLogin(
      new AutoLoginCommand(dto.refreshToken, dto.deviceId),
    );
  }

  @Public()
  @Post('send-sms-code')
  @ApiOperation({ summary: '发送短信验证码' })
  async sendSmsCode(@Body() dto: SendSmsCodeDto) {
    await this.userService.sendSmsCode(
      new SendSmsCodeCommand(dto.phoneNumber, dto.type),
    );
    return { message: '验证码已发送' };
  }

  @Public()
  @Post('verify-sms-code')
  @ApiOperation({
    summary: '验证短信验证码',
    description: '仅验证验证码是否正确，不进行登录或注册',
  })
  @ApiResponse({ status: 200, description: '验证成功' })
  async verifySmsCode(@Body() dto: VerifySmsCodeDto) {
    await this.userService.verifySmsCode(
      new VerifySmsCodeCommand(
        dto.phoneNumber,
        dto.smsCode,
        dto.type as 'REGISTER' | 'LOGIN' | 'BIND' | 'RECOVER' | 'RESET_PASSWORD',
      ),
    );
    return { message: '验证成功' };
  }

  @Public()
  @Post('send-reset-password-sms')
  @ApiOperation({
    summary: '发送重置密码短信验证码',
    description: '向已注册的手机号发送重置密码验证码',
  })
  @ApiResponse({ status: 200, description: '验证码已发送' })
  async sendResetPasswordSms(@Body() body: { phoneNumber: string }) {
    await this.userService.sendResetPasswordSmsCode(body.phoneNumber);
    return { message: '验证码已发送' };
  }

  @Public()
  @Post('reset-password')
  @ApiOperation({
    summary: '重置密码',
    description: '通过手机号+短信验证码重置登录密码',
  })
  @ApiResponse({ status: 200, description: '密码重置成功' })
  async resetPassword(@Body() dto: ResetPasswordDto) {
    await this.userService.resetPassword(
      dto.phoneNumber,
      dto.smsCode,
      dto.newPassword,
    );
    return { message: '密码重置成功' };
  }

  @Public()
  @Post('register')
  @ApiOperation({ summary: '用户注册(手机号)' })
  @ApiResponse({ status: 200, type: LoginResponseDto })
  async register(@Body() dto: RegisterDto) {
    return this.userService.register(
      new RegisterCommand(
        dto.phoneNumber,
        dto.smsCode,
        dto.deviceId,
        dto.deviceName,
        dto.inviterReferralCode,
      ),
    );
  }

  @Public()
  @Post('login')
  @ApiOperation({ summary: '用户登录(手机号+短信验证码)' })
  @ApiResponse({ status: 200, type: LoginResponseDto })
  async login(@Body() dto: LoginDto) {
    return this.userService.login(
      new LoginCommand(dto.phoneNumber, dto.smsCode, dto.deviceId),
    );
  }

  @Public()
  @Post('login-with-password')
  @ApiOperation({
    summary: '用户登录(手机号+密码)',
    description: '用于账号恢复，使用手机号和密码登录',
  })
  @ApiResponse({ status: 200, type: LoginResponseDto })
  async loginWithPassword(@Body() dto: LoginWithPasswordDto) {
    return this.userService.loginWithPassword(
      dto.phoneNumber,
      dto.password,
      dto.deviceId,
    );
  }

  @Post('bind-phone')
  @ApiBearerAuth()
  @ApiOperation({ summary: '绑定手机号' })
  async bindPhone(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: BindPhoneDto,
  ) {
    await this.userService.bindPhoneNumber(
      new BindPhoneNumberCommand(user.userId, dto.phoneNumber, dto.smsCode),
    );
    return { message: '绑定成功' };
  }

  @Post('set-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '设置登录密码',
    description: '首次设置或修改登录密码',
  })
  @ApiResponse({ status: 200, description: '密码设置成功' })
  async setPassword(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: SetPasswordDto,
  ) {
    await this.userService.setPassword(
      new SetPasswordCommand(user.userId, dto.password),
    );
    return { message: '密码设置成功' };
  }

  @Post('change-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '修改登录密码',
    description: '验证旧密码后修改为新密码',
  })
  @ApiResponse({ status: 200, description: '密码修改成功' })
  @ApiResponse({ status: 400, description: '旧密码错误' })
  async changePassword(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: ChangePasswordDto,
  ) {
    await this.userService.changePassword(
      new ChangePasswordCommand(user.userId, dto.oldPassword, dto.newPassword),
    );
    return { message: '密码修改成功' };
  }

  // ============ 邮箱绑定相关 ============

  @Get('email-status')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '获取邮箱绑定状态',
    description: '查询当前用户的邮箱绑定状态和脱敏后的邮箱地址',
  })
  @ApiResponse({
    status: 200,
    description: '邮箱状态',
    schema: {
      properties: {
        isBound: { type: 'boolean', description: '是否已绑定邮箱' },
        email: { type: 'string', nullable: true, description: '脱敏后的邮箱地址' },
      },
    },
  })
  async getEmailStatus(@CurrentUser() user: CurrentUserData) {
    return this.userService.getEmailStatus(user.userId);
  }

  @Post('send-email-code')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '发送邮箱验证码',
    description: '发送绑定/解绑邮箱的验证码到指定邮箱',
  })
  @ApiResponse({ status: 200, description: '验证码发送成功' })
  @ApiResponse({ status: 400, description: '邮箱已被其他账户绑定' })
  async sendEmailCode(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: SendEmailCodeDto,
  ) {
    await this.userService.sendEmailCode(
      new SendEmailCodeCommand(user.userId, dto.email, dto.purpose),
    );
    return { message: '验证码已发送' };
  }

  @Post('bind-email')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '绑定邮箱',
    description: '使用验证码绑定邮箱地址',
  })
  @ApiResponse({ status: 200, description: '邮箱绑定成功' })
  @ApiResponse({ status: 400, description: '验证码错误或已过期' })
  async bindEmail(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: BindEmailDto,
  ) {
    await this.userService.bindEmail(
      new BindEmailCommand(user.userId, dto.email, dto.code),
    );
    return { message: '邮箱绑定成功' };
  }

  @Post('unbind-email')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '解绑邮箱',
    description: '使用验证码解绑当前绑定的邮箱',
  })
  @ApiResponse({ status: 200, description: '邮箱解绑成功' })
  @ApiResponse({ status: 400, description: '验证码错误或已过期' })
  async unbindEmail(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: UnbindEmailDto,
  ) {
    await this.userService.unbindEmail(
      new UnbindEmailCommand(user.userId, dto.code),
    );
    return { message: '邮箱解绑成功' };
  }

  // ============ 更换手机号 ============

  @Get('phone-status')
  @ApiBearerAuth()
  @ApiOperation({ summary: '获取手机号状态' })
  @ApiResponse({ status: 200, description: '返回手机号绑定和验证状态' })
  async getPhoneStatus(@CurrentUser() user: CurrentUserData) {
    return this.userService.getPhoneStatus(user.userId);
  }

  @Post('change-phone/send-old-code')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '发送旧手机验证码',
    description: '更换手机号第一步：向当前绑定的手机号发送验证码',
  })
  @ApiResponse({ status: 200, description: '验证码已发送' })
  async sendOldPhoneCode(@CurrentUser() user: CurrentUserData) {
    await this.userService.sendOldPhoneCode(user.userId);
    return { message: '验证码已发送' };
  }

  @Post('change-phone/verify-old')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '验证旧手机验证码',
    description: '更换手机号第二步：验证旧手机验证码，成功后返回临时令牌',
  })
  @ApiResponse({ status: 200, description: '验证成功，返回临时令牌' })
  async verifyOldPhoneCode(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: VerifyOldPhoneDto,
  ) {
    return this.userService.verifyOldPhoneCode(user.userId, dto.smsCode);
  }

  @Post('change-phone/send-new-code')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '发送新手机验证码',
    description: '更换手机号第三步：向新手机号发送验证码',
  })
  @ApiResponse({ status: 200, description: '验证码已发送' })
  async sendNewPhoneCode(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: SendNewPhoneCodeDto,
  ) {
    await this.userService.sendNewPhoneCode(
      user.userId,
      dto.newPhoneNumber,
      dto.changePhoneToken,
    );
    return { message: '验证码已发送' };
  }

  @Post('change-phone/confirm')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '确认更换手机号',
    description: '更换手机号第四步：验证新手机验证码并完成更换',
  })
  @ApiResponse({ status: 200, description: '手机号更换成功' })
  async confirmChangePhone(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: ConfirmChangePhoneDto,
  ) {
    await this.userService.confirmChangePhone(
      user.userId,
      dto.newPhoneNumber,
      dto.smsCode,
      dto.changePhoneToken,
    );
    return { message: '手机号更换成功' };
  }

  @Get('my-profile')
  @ApiBearerAuth()
  @ApiOperation({ summary: '查询我的资料' })
  @ApiResponse({ status: 200, type: UserProfileResponseDto })
  async getMyProfile(@CurrentUser() user: CurrentUserData) {
    return this.userService.getMyProfile(new GetMyProfileQuery(user.userId));
  }

  @Put('update-profile')
  @ApiBearerAuth()
  @ApiOperation({ summary: '更新用户资料' })
  async updateProfile(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: UpdateProfileDto,
  ) {
    await this.userService.updateProfile(
      new UpdateProfileCommand(user.userId, dto.nickname, dto.avatarUrl),
    );
    return { message: '更新成功' };
  }

  @Post('submit-kyc')
  @ApiBearerAuth()
  @ApiOperation({ summary: '提交KYC认证' })
  async submitKYC(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: SubmitKYCDto,
  ) {
    await this.userService.submitKYC(
      new SubmitKYCCommand(
        user.userId,
        dto.realName,
        dto.idCardNumber,
        dto.idCardFrontUrl,
        dto.idCardBackUrl,
      ),
    );
    return { message: '提交成功' };
  }

  @Get('my-devices')
  @ApiBearerAuth()
  @ApiOperation({ summary: '查看我的设备列表' })
  @ApiResponse({ status: 200, type: [DeviceResponseDto] })
  async getMyDevices(@CurrentUser() user: CurrentUserData) {
    return this.userService.getMyDevices(
      new GetMyDevicesQuery(user.userId, user.deviceId),
    );
  }

  @Post('remove-device')
  @ApiBearerAuth()
  @ApiOperation({ summary: '移除设备' })
  async removeDevice(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: RemoveDeviceDto,
  ) {
    await this.userService.removeDevice(
      new RemoveDeviceCommand(user.userId, user.deviceId, dto.deviceId),
    );
    return { message: '移除成功' };
  }

  @Public()
  @Get('by-referral-code/:code')
  @ApiOperation({ summary: '根据推荐码查询用户' })
  async getByReferralCode(@Param('code') code: string) {
    return this.userService.getUserByReferralCode(
      new GetUserByReferralCodeQuery(code),
    );
  }

  @Get('wallet')
  @ApiBearerAuth()
  @ApiOperation({ summary: '获取我的钱包状态和地址' })
  @ApiResponse({
    status: 200,
    description: '钱包已就绪',
    type: WalletStatusReadyResponseDto,
  })
  @ApiResponse({
    status: 202,
    description: '钱包生成中',
    type: WalletStatusGeneratingResponseDto,
  })
  async getWalletStatus(@CurrentUser() user: CurrentUserData) {
    return this.userService.getWalletStatus(
      new GetWalletStatusQuery(user.accountSequence),
    );
  }

  @Post('wallet/retry')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '手动重试钱包生成',
    description: '当钱包生成失败或超时时，用户可手动触发重试',
  })
  @ApiResponse({ status: 200, description: '重试请求已提交' })
  async retryWalletGeneration(@CurrentUser() user: CurrentUserData) {
    await this.userService.retryWalletGeneration(user.userId);
    return { message: '钱包生成重试已触发，请稍后查询钱包状态' };
  }

  @Put('mnemonic/backup')
  @ApiBearerAuth()
  @ApiOperation({ summary: '标记助记词已备份' })
  @ApiResponse({ status: 200, description: '标记成功' })
  async markMnemonicBackedUp(@CurrentUser() user: CurrentUserData) {
    await this.userService.markMnemonicBackedUp(
      new MarkMnemonicBackedUpCommand(user.userId),
    );
    return { message: '已标记为已备份' };
  }

  @Post('mnemonic/revoke')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '挂失助记词',
    description: '用户主动挂失助记词，挂失后该助记词将无法用于账户恢复',
  })
  @ApiResponse({ status: 200, description: '挂失结果' })
  async revokeMnemonic(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: RevokeMnemonicDto,
  ) {
    return this.userService.revokeMnemonic(user.userId, dto.reason);
  }

  @Post('freeze')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '冻结账户',
    description: '用户主动冻结自己的账户，冻结后账户将无法进行任何操作',
  })
  @ApiResponse({ status: 200, description: '冻结结果' })
  async freezeAccount(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: FreezeAccountDto,
  ) {
    return this.userService.freezeAccount(user.userId, dto.reason);
  }

  @Post('unfreeze')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '解冻账户',
    description: '验证身份后解冻账户，支持助记词或手机号验证',
  })
  @ApiResponse({ status: 200, description: '解冻结果' })
  async unfreezeAccount(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: UnfreezeAccountDto,
  ) {
    return this.userService.unfreezeAccount({
      userId: user.userId,
      verifyMethod: dto.verifyMethod,
      mnemonic: dto.mnemonic,
      phoneNumber: dto.phoneNumber,
      smsCode: dto.smsCode,
    });
  }

  @Post('key-rotation/request')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '请求密钥轮换',
    description: '验证当前助记词后，请求轮换 MPC 密钥对',
  })
  @ApiResponse({ status: 200, description: '轮换请求结果' })
  async requestKeyRotation(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: RequestKeyRotationDto,
  ) {
    return this.userService.requestKeyRotation({
      userId: user.userId,
      currentMnemonic: dto.currentMnemonic,
      reason: dto.reason,
    });
  }

  @Post('backup-codes/generate')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '生成恢复码',
    description: '验证助记词后生成一组一次性恢复码',
  })
  @ApiResponse({ status: 200, description: '恢复码列表' })
  async generateBackupCodes(
    @CurrentUser() user: CurrentUserData,
    @Body() dto: GenerateBackupCodesDto,
  ) {
    return this.userService.generateBackupCodes({
      userId: user.userId,
      mnemonic: dto.mnemonic,
    });
  }

  @Public()
  @Post('recover-by-backup-code')
  @ApiOperation({ summary: '使用恢复码恢复账户' })
  @ApiResponse({ status: 200, type: RecoverAccountResponseDto })
  async recoverByBackupCode(@Body() dto: RecoverByBackupCodeDto) {
    return this.userService.recoverByBackupCode({
      accountSequence: dto.accountSequence,
      backupCode: dto.backupCode,
      newDeviceId: dto.newDeviceId,
      deviceName: dto.deviceName,
    });
  }

  @Post('sms/send-withdraw-code')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '发送提取验证短信',
    description: '向用户绑定的手机号发送提取验证码',
  })
  @ApiResponse({ status: 200, description: '发送成功' })
  async sendWithdrawSmsCode(@CurrentUser() user: CurrentUserData) {
    await this.userService.sendWithdrawSmsCode(user.userId);
    return { message: '验证码已发送' };
  }

  @Post('sms/verify-withdraw-code')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '验证提取短信验证码',
    description: '验证提取操作的短信验证码',
  })
  @ApiResponse({ status: 200, description: '验证结果' })
  async verifyWithdrawSmsCode(
    @CurrentUser() user: CurrentUserData,
    @Body() body: { code: string },
  ) {
    const valid = await this.userService.verifyWithdrawSmsCode(
      user.userId,
      body.code,
    );
    return { valid };
  }

  @Post('verify-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '验证登录密码',
    description: '验证用户的登录密码，用于敏感操作二次验证',
  })
  @ApiResponse({ status: 200, description: '验证结果' })
  async verifyPassword(
    @CurrentUser() user: CurrentUserData,
    @Body() body: { password: string },
  ) {
    const valid = await this.userService.verifyPassword(
      user.userId,
      body.password,
    );
    return { valid };
  }

  // ============ 密码状态查询 ============

  @Get('password-status')
  @ApiBearerAuth()
  @ApiOperation({ summary: '查询登录密码状态', description: '查询当前用户是否已设置登录密码' })
  @ApiResponse({ status: 200, description: '{ isSet: boolean }' })
  async getPasswordStatus(@CurrentUser() user: CurrentUserData) {
    const isSet = await this.userService.isLoginPasswordSet(user.userId);
    return { isSet };
  }

  // ============ 支付密码相关 ============

  @Get('payment-password-status')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '查询支付密码状态',
    description: '查询当前用户是否已设置支付密码',
  })
  @ApiResponse({ status: 200, description: '{ isSet: boolean }' })
  async getPaymentPasswordStatus(@CurrentUser() user: CurrentUserData) {
    const isSet = await this.userService.isPaymentPasswordSet(user.userId);
    return { isSet };
  }

  @Post('set-payment-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '设置支付密码',
    description: '首次设置支付密码（无需旧密码）',
  })
  @ApiResponse({ status: 200, description: '设置成功' })
  @ApiResponse({ status: 400, description: '支付密码已设置' })
  async setPaymentPassword(
    @CurrentUser() user: CurrentUserData,
    @Body() body: { password: string },
  ) {
    await this.userService.setPaymentPassword({
      userId: user.userId,
      password: body.password,
    });
    return { message: '支付密码设置成功' };
  }

  @Post('change-payment-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '修改支付密码',
    description: '验证旧支付密码后修改为新支付密码',
  })
  @ApiResponse({ status: 200, description: '修改成功' })
  @ApiResponse({ status: 400, description: '旧支付密码错误' })
  async changePaymentPassword(
    @CurrentUser() user: CurrentUserData,
    @Body() body: { oldPassword: string; newPassword: string },
  ) {
    await this.userService.changePaymentPassword({
      userId: user.userId,
      oldPassword: body.oldPassword,
      newPassword: body.newPassword,
    });
    return { message: '支付密码修改成功' };
  }

  @Post('verify-payment-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '验证支付密码',
    description: '验证用户的支付密码，用于认种/预种等支付操作二次验证',
  })
  @ApiResponse({ status: 200, description: '{ valid: boolean }' })
  async verifyPaymentPassword(
    @CurrentUser() user: CurrentUserData,
    @Body() body: { password: string },
  ) {
    const valid = await this.userService.verifyPaymentPassword(
      user.userId,
      body.password,
    );
    return { valid };
  }

  // ============ 找回支付密码相关 ============

  /**
   * 发送重置支付密码短信验证码
   *
   * 向当前登录用户绑定的手机号发送验证码，用于忘记支付密码时的身份核验。
   * 接口需要 Bearer Token（只有已登录用户才能重置支付密码）。
   */
  @Post('send-reset-payment-password-sms')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '发送重置支付密码短信验证码',
    description: '向当前登录用户绑定的手机号发送验证码，用于忘记支付密码时验证身份',
  })
  @ApiResponse({ status: 200, description: '验证码已发送' })
  async sendResetPaymentPasswordSms(@CurrentUser() user: CurrentUserData) {
    await this.userService.sendResetPaymentPasswordSmsCode(user.userId);
    return { message: '验证码已发送' };
  }

  /**
   * 重置支付密码
   *
   * 通过短信验证码验证身份后，将支付密码重置为新的 6 位数字密码。
   * 接口需要 Bearer Token（只有已登录用户才能重置支付密码）。
   */
  @Post('reset-payment-password')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '重置支付密码',
    description: '通过短信验证码验证身份后重置支付密码（用于忘记支付密码场景）',
  })
  @ApiResponse({ status: 200, description: '支付密码重置成功' })
  @ApiResponse({ status: 400, description: '验证码错误或密码格式不正确' })
  async resetPaymentPassword(
    @CurrentUser() user: CurrentUserData,
    @Body() body: { smsCode: string; newPassword: string },
  ) {
    await this.userService.resetPaymentPassword(
      user.userId,
      body.smsCode,
      body.newPassword,
    );
    return { message: '支付密码重置成功' };
  }

  @Get('users/resolve-address/:accountSequence')
  @ApiBearerAuth()
  @ApiOperation({
    summary: '解析充值ID到区块链地址',
    description: '通过用户的 accountSequence 获取其区块链钱包地址',
  })
  @ApiResponse({ status: 200, description: '返回区块链地址' })
  @ApiResponse({ status: 404, description: '找不到用户' })
  async resolveAccountSequenceToAddress(
    @Param('accountSequence') accountSequence: string,
  ) {
    // 默认返回 KAVA 链地址（支持所有 EVM 链）
    const address = await this.userService.resolveAccountSequenceToAddress(
      accountSequence,
      'KAVA',
    );
    return { address };
  }

  @Get('internal/users/by-wallet-address')
  @Public()
  @ApiOperation({
    summary: '通过钱包地址查询用户信息（内部调用）',
    description: '通过区块链钱包地址查询用户的 accountSequence 和 userId',
  })
  @ApiQuery({ name: 'chainType', required: true, description: '链类型 (KAVA/BSC)' })
  @ApiQuery({ name: 'address', required: true, description: '钱包地址' })
  @ApiResponse({ status: 200, description: '返回用户信息' })
  @ApiResponse({ status: 404, description: '找不到用户' })
  async getUserByWalletAddress(
    @Query('chainType') chainType: string,
    @Query('address') address: string,
  ) {
    const result = await this.userService.findUserByWalletAddress(chainType, address);
    if (!result) {
      return { found: false, accountSequence: null, userId: null };
    }
    return {
      found: true,
      accountSequence: result.accountSequence,
      userId: result.userId.toString(),
    };
  }

  @Get('internal/users/by-account-sequence/:accountSequence')
  @Public()
  @ApiOperation({
    summary: '通过 accountSequence 查询用户信息（内部调用）',
    description: '通过用户的 accountSequence 查询详细信息，包括钱包地址',
  })
  @ApiParam({ name: 'accountSequence', description: '账户序列号 (如 D25121400005)' })
  @ApiResponse({ status: 200, description: '返回用户信息' })
  @ApiResponse({ status: 404, description: '找不到用户' })
  async getUserByAccountSequence(
    @Param('accountSequence') accountSequence: string,
  ) {
    const result = await this.userService.findUserByAccountSequence(accountSequence);
    if (!result) {
      return { found: false, accountSequence: null, userId: null, realName: null, walletAddress: null };
    }
    return {
      found: true,
      accountSequence: result.accountSequence,
      userId: result.userId.toString(),
      realName: result.realName,
      walletAddress: result.walletAddress,
    };
  }

  @Post('upload-avatar')
  @ApiBearerAuth()
  @ApiOperation({ summary: '上传用户头像' })
  @ApiConsumes('multipart/form-data')
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
          description: '头像图片文件 (支持 jpg, png, gif, webp, 最大5MB)',
        },
      },
    },
  })
  @ApiResponse({ status: 200, description: '上传成功，返回头像URL' })
  @UseInterceptors(FileInterceptor('file'))
  async uploadAvatar(
    @CurrentUser() user: CurrentUserData,
    @UploadedFile() file: Express.Multer.File,
  ) {
    // 验证文件是否存在
    if (!file) {
      throw new BadRequestException('请选择要上传的图片');
    }

    // 验证文件类型
    if (!this.storageService.isValidImageType(file.mimetype)) {
      throw new BadRequestException(
        '不支持的图片格式，请使用 jpg, png, gif 或 webp',
      );
    }

    // 验证文件大小
    if (file.size > this.storageService.maxAvatarSize) {
      throw new BadRequestException('图片大小不能超过 5MB');
    }

    // 上传文件
    const result = await this.storageService.uploadAvatar(
      user.userId,
      file.buffer,
      file.mimetype,
    );

    // 更新用户头像URL
    await this.userService.updateProfile(
      new UpdateProfileCommand(user.userId, undefined, result.url),
    );

    return {
      message: '上传成功',
      avatarUrl: result.url,
    };
  }

  @Post('upload-image')
  @ApiBearerAuth()
  @ApiOperation({ summary: '上传通用图片' })
  @ApiConsumes('multipart/form-data')
  @ApiQuery({
    name: 'category',
    description: '图片分类 (如 office-photos)',
    example: 'office-photos',
  })
  @ApiBody({
    schema: {
      type: 'object',
      properties: {
        file: {
          type: 'string',
          format: 'binary',
          description: '图片文件 (支持 jpg, png, gif, webp, 最大10MB)',
        },
      },
    },
  })
  @ApiResponse({ status: 200, description: '上传成功，返回图片URL' })
  @UseInterceptors(FileInterceptor('file'))
  async uploadImage(
    @CurrentUser() user: CurrentUserData,
    @Query('category') category: string,
    @UploadedFile() file: Express.Multer.File,
  ) {
    // 验证分类
    if (!category || category.trim() === '') {
      throw new BadRequestException('请指定图片分类');
    }

    // 验证文件是否存在
    if (!file) {
      throw new BadRequestException('请选择要上传的图片');
    }

    // 验证文件类型
    if (!this.storageService.isValidImageType(file.mimetype)) {
      throw new BadRequestException(
        '不支持的图片格式，请使用 jpg, png, gif 或 webp',
      );
    }

    // 验证文件大小
    if (file.size > this.storageService.maxImageSize) {
      throw new BadRequestException('图片大小不能超过 10MB');
    }

    // 上传文件
    const result = await this.storageService.uploadImage(
      user.userId,
      category.trim(),
      file.buffer,
      file.mimetype,
    );

    return {
      message: '上传成功',
      imageUrl: result.url,
      key: result.key,
      size: result.size,
    };
  }
}
