import { Controller, Get, Post, Body, Query, UseGuards, Headers, HttpException, HttpStatus } from '@nestjs/common';
import { ApiTags, ApiOperation, ApiBearerAuth, ApiResponse, ApiQuery } from '@nestjs/swagger';
import { WalletApplicationService } from '@/application/services';
import { GetMyWalletQuery } from '@/application/queries';
import { ClaimRewardsCommand, SettleRewardsCommand, RequestWithdrawalCommand } from '@/application/commands';
import { CurrentUser, CurrentUserPayload } from '@/shared/decorators';
import { JwtAuthGuard } from '@/shared/guards/jwt-auth.guard';
import { SettleRewardsDTO, RequestWithdrawalDTO } from '@/api/dto/request';
import { WalletResponseDTO, WithdrawalResponseDTO, WithdrawalListItemDTO, WithdrawalFeeConfigResponseDTO, CalculateFeeResponseDTO } from '@/api/dto/response';
import { IdentityClientService } from '@/infrastructure/external/identity';
import { FeeConfigRepositoryImpl } from '@/infrastructure/persistence/repositories';

@ApiTags('Wallet')
@Controller('wallet')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth()
export class WalletController {
  constructor(
    private readonly walletService: WalletApplicationService,
    private readonly identityClient: IdentityClientService,
    private readonly feeConfigRepo: FeeConfigRepositoryImpl,
  ) {}

  @Get('my-wallet')
  @ApiOperation({ summary: '查询我的钱包', description: '获取当前用户的钱包余额、算力和奖励信息' })
  @ApiResponse({ status: 200, type: WalletResponseDTO })
  async getMyWallet(@CurrentUser() user: CurrentUserPayload): Promise<WalletResponseDTO> {
    const query = new GetMyWalletQuery(
      user.accountSequence,
      user.userId,
    );
    return this.walletService.getMyWallet(query);
  }

  @Post('claim-rewards')
  @ApiOperation({ summary: '领取奖励', description: '将待领取的奖励转为可结算状态' })
  @ApiResponse({ status: 200, description: '领取成功' })
  async claimRewards(@CurrentUser() user: CurrentUserPayload): Promise<{ message: string }> {
    const command = new ClaimRewardsCommand(user.userId);
    await this.walletService.claimRewards(command);
    return { message: 'Rewards claimed successfully' };
  }

  @Post('settle')
  @ApiOperation({ summary: '结算收益', description: '将可结算的USDT兑换为指定币种' })
  @ApiResponse({ status: 200, description: '结算成功' })
  async settleRewards(
    @CurrentUser() user: CurrentUserPayload,
    @Body() dto: SettleRewardsDTO,
  ): Promise<{ settlementOrderId: string }> {
    const command = new SettleRewardsCommand(
      user.userId,
      dto.usdtAmount,
      dto.settleCurrency,
    );
    const orderId = await this.walletService.settleRewards(command);
    return { settlementOrderId: orderId };
  }

  @Post('withdraw/send-sms')
  @ApiOperation({ summary: '发送提取验证短信', description: '向用户手机发送提取验证码' })
  @ApiResponse({ status: 200, description: '发送成功' })
  async sendWithdrawSms(
    @CurrentUser() user: CurrentUserPayload,
    @Headers('authorization') authHeader: string,
  ): Promise<{ message: string }> {
    const token = authHeader?.replace('Bearer ', '') || '';

    // 调用 identity-service 发送短信验证码
    await this.identityClient.sendWithdrawSmsCode(user.userId, token);
    return { message: '验证码已发送' };
  }

  @Post('withdraw')
  @ApiOperation({ summary: '申请提现', description: '将USDT提现到指定地址，需要短信验证和密码验证' })
  @ApiResponse({ status: 201, type: WithdrawalResponseDTO })
  async requestWithdrawal(
    @CurrentUser() user: CurrentUserPayload,
    @Body() dto: RequestWithdrawalDTO,
    @Headers('authorization') authHeader: string,
  ): Promise<WithdrawalResponseDTO> {
    // 提取 JWT token
    const token = authHeader?.replace('Bearer ', '') || '';

    // 验证短信验证码
    if (!dto.smsCode) {
      throw new HttpException('请输入短信验证码', HttpStatus.BAD_REQUEST);
    }

    const isSmsValid = await this.identityClient.verifyWithdrawSmsCode(user.userId, dto.smsCode, token);
    if (!isSmsValid) {
      throw new HttpException('短信验证码错误，请重试', HttpStatus.BAD_REQUEST);
    }

    // 验证登录密码
    if (!dto.password) {
      throw new HttpException('请输入登录密码', HttpStatus.BAD_REQUEST);
    }

    const isPasswordValid = await this.identityClient.verifyPassword(user.userId, dto.password, token);
    if (!isPasswordValid) {
      throw new HttpException('登录密码错误，请重试', HttpStatus.BAD_REQUEST);
    }

    // 处理 toAddress: 如果是 accountSequence 格式，转换为区块链地址
    let actualAddress = dto.toAddress;
    if (dto.toAddress.startsWith('D') && dto.toAddress.length === 12) {
      // accountSequence 格式，需要查询对应的区块链地址
      const resolvedAddress = await this.identityClient.resolveAccountSequenceToAddress(
        dto.toAddress,
        dto.chainType,
        token,
      );
      if (!resolvedAddress) {
        throw new HttpException('无效的充值ID，未找到对应地址', HttpStatus.BAD_REQUEST);
      }
      actualAddress = resolvedAddress;
    }

    // [2026-01-16] 使用 accountSequence 而非 userId 查找钱包
    // 背景：发现幽灵钱包 D26010800000 (user_id=133, 余额=0) 导致真实用户 D26010900000 (user_id=0, 余额=200465) 转账失败
    // 原因：D26010800000 是 2026-01-08 16:23 通过未知方式创建的脏数据，占用了 user_id=133
    //       而真实用户 D26010900000 在 2026-01-08 18:40 注册时，因 user_id=133 已被占用，其钱包 user_id 被设为 0
    // 问题：getMyWallet 用 accountSequence 查询显示余额正确，但 requestWithdrawal 用 userId 查询找到错误的空钱包
    // 修复：统一使用 accountSequence 作为钱包查询的唯一标识
    const command = new RequestWithdrawalCommand(
      user.accountSequence,
      dto.amount,
      actualAddress,
      dto.chainType,
    );
    return this.walletService.requestWithdrawal(command);
  }

  @Get('withdrawals')
  @ApiOperation({ summary: '查询提现记录', description: '获取用户的提现订单列表' })
  @ApiResponse({ status: 200, type: [WithdrawalListItemDTO] })
  async getWithdrawals(
    @CurrentUser() user: CurrentUserPayload,
  ): Promise<WithdrawalListItemDTO[]> {
    return this.walletService.getWithdrawals(user.accountSequence);
  }

  @Get('pending-rewards')
  @ApiOperation({ summary: '查询待领取奖励列表', description: '获取用户的逐笔待领取奖励，包含过期时间' })
  @ApiResponse({ status: 200, description: '待领取奖励列表' })
  async getPendingRewards(
    @CurrentUser() user: CurrentUserPayload,
  ): Promise<Array<{
    id: string;
    usdtAmount: number;
    hashpowerAmount: number;
    sourceOrderId: string;
    allocationType: string;
    expireAt: string;
    status: string;
    createdAt: string;
  }>> {
    return this.walletService.getPendingRewards(user.accountSequence);
  }

  @Get('settleable-rewards')
  @ApiOperation({ summary: '查询可结算奖励列表', description: '获取用户的逐笔可结算奖励（已领取待结算）' })
  @ApiResponse({ status: 200, description: '可结算奖励列表' })
  async getSettleableRewards(
    @CurrentUser() user: CurrentUserPayload,
  ): Promise<Array<{
    id: string;
    usdtAmount: number;
    hashpowerAmount: number;
    sourceOrderId: string;
    allocationType: string;
    settledAt: string;
    createdAt: string;
  }>> {
    return this.walletService.getSettleableRewards(user.accountSequence);
  }

  /**
   * [2026-03-01] 预种可结算收益结算
   *
   * 预种奖励不经过 reward-service，因此 reward-service 的一键结算无法覆盖预种部分。
   * mobile-app 在调用 reward-service settleToBalance 之后，再调本端点结算 wallet 中剩余的 settleable_usdt。
   * 如果 settleable_usdt=0（已被 reward-service 全部结算），本端点直接返回 success，不做任何操作。
   */
  @Post('settle-pre-planting')
  @ApiOperation({ summary: '结算预种可结算收益', description: '将预种部分的可结算USDT转入钱包余额（reward-service 一键结算后调用）' })
  @ApiResponse({ status: 200, description: '结算结果' })
  async settlePrePlanting(@CurrentUser() user: CurrentUserPayload): Promise<{
    success: boolean;
    settlementId: string;
    settledAmount: number;
    balanceAfter: number;
    error?: string;
  }> {
    return this.walletService.settlePrePlantingToBalance(user.accountSequence);
  }

  @Get('expired-rewards')
  @ApiOperation({ summary: '查询已过期奖励列表', description: '获取用户的逐笔已过期奖励（24h未领取）' })
  @ApiResponse({ status: 200, description: '已过期奖励列表' })
  async getExpiredRewards(
    @CurrentUser() user: CurrentUserPayload,
  ): Promise<Array<{
    id: string;
    usdtAmount: number;
    hashpowerAmount: number;
    sourceOrderId: string;
    allocationType: string;
    expiredAt: string;
    createdAt: string;
  }>> {
    return this.walletService.getExpiredRewards(user.accountSequence);
  }

  @Get('fee-config')
  @ApiOperation({ summary: '查询提取手续费配置', description: '获取当前生效的提取手续费配置' })
  @ApiResponse({ status: 200, type: WithdrawalFeeConfigResponseDTO })
  async getFeeConfig(): Promise<WithdrawalFeeConfigResponseDTO> {
    return this.feeConfigRepo.getActiveConfig();
  }

  @Get('calculate-fee')
  @ApiOperation({ summary: '计算提取手续费', description: '根据提取金额计算手续费' })
  @ApiQuery({ name: 'amount', type: Number, description: '提取金额' })
  @ApiResponse({ status: 200, type: CalculateFeeResponseDTO })
  async calculateFee(
    @Query('amount') amountStr: string,
  ): Promise<CalculateFeeResponseDTO> {
    const amount = parseFloat(amountStr);
    if (isNaN(amount) || amount <= 0) {
      throw new HttpException('无效的金额', HttpStatus.BAD_REQUEST);
    }

    const { fee, feeType, feeValue } = await this.feeConfigRepo.calculateFee(amount);

    return {
      amount,
      fee,
      totalRequired: amount + fee,
      receiverGets: amount, // 接收方收到完整金额
      feeType,
      feeValue,
    };
  }
}
