import { Injectable, Inject, Logger, BadRequestException } from '@nestjs/common';
import {
  IWalletAccountRepository, WALLET_ACCOUNT_REPOSITORY,
  ILedgerEntryRepository, LEDGER_ENTRY_REPOSITORY,
  IFiatWithdrawalOrderRepository, FIAT_WITHDRAWAL_ORDER_REPOSITORY,
} from '@/domain/repositories';
import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service';
import { FiatWithdrawalOrder, LedgerEntry, PaymentAccountInfo } from '@/domain/aggregates';
import { UserId, Money, LedgerEntryType } from '@/domain/value-objects';
import { FiatWithdrawalStatus, PaymentMethod } from '@/domain/value-objects/fiat-withdrawal-status.enum';
import { WalletNotFoundError, OptimisticLockError } from '@/shared/exceptions/domain.exception';
import { WalletCacheService } from '@/infrastructure/redis';
import { FeeConfigRepositoryImpl } from '@/infrastructure/persistence/repositories';
import { FeeType } from '@/api/dto/response';
import Decimal from 'decimal.js';

/**
 * 法币提现请求命令
 */
export interface RequestFiatWithdrawalCommand {
  accountSequence: string;
  userId: string;
  amount: number;
  paymentMethod: PaymentMethod;
  // 银行卡
  bankName?: string;
  bankCardNo?: string;
  cardHolderName?: string;
  // 支付宝
  alipayAccount?: string;
  alipayRealName?: string;
  // 微信
  wechatAccount?: string;
  wechatRealName?: string;
}

/**
 * 审核命令
 */
export interface ReviewFiatWithdrawalCommand {
  orderNo: string;
  approved: boolean;
  reviewedBy: string;
  remark?: string;
}

/**
 * 打款命令
 */
export interface StartPaymentCommand {
  orderNo: string;
  paidBy: string;
}

export interface CompletePaymentCommand {
  orderNo: string;
  paymentProof?: string;
  remark?: string;
}

/**
 * 法币提现响应 DTO
 */
export interface FiatWithdrawalResponseDTO {
  orderNo: string;
  amount: number;
  fee: number;
  netAmount: number;
  status: string;
  paymentMethod: string;
}

/**
 * 法币提现订单列表项 DTO
 */
export interface FiatWithdrawalListItemDTO {
  orderNo: string;
  accountSequence: string;
  userId: string;
  amount: number;
  fee: number;
  netAmount: number;
  paymentMethod: string;
  paymentMethodName: string;
  paymentAccountDisplay: string;
  status: string;
  reviewedBy: string | null;
  reviewedAt: string | null;
  reviewRemark: string | null;
  paidBy: string | null;
  paidAt: string | null;
  frozenAt: string | null;
  completedAt: string | null;
  createdAt: string;
}

/**
 * 法币提现应用服务
 *
 * 处理法币提现相关的业务逻辑：
 * 1. 用户申请提现
 * 2. 管理员审核
 * 3. 管理员打款
 */
@Injectable()
export class FiatWithdrawalApplicationService {
  private readonly logger = new Logger(FiatWithdrawalApplicationService.name);
  private readonly MIN_WITHDRAWAL_AMOUNT = 100; // 最小提现金额

  constructor(
    @Inject(WALLET_ACCOUNT_REPOSITORY)
    private readonly walletRepo: IWalletAccountRepository,
    @Inject(LEDGER_ENTRY_REPOSITORY)
    private readonly ledgerRepo: ILedgerEntryRepository,
    @Inject(FIAT_WITHDRAWAL_ORDER_REPOSITORY)
    private readonly fiatWithdrawalRepo: IFiatWithdrawalOrderRepository,
    private readonly walletCacheService: WalletCacheService,
    private readonly prisma: PrismaService,
    private readonly feeConfigRepo: FeeConfigRepositoryImpl,
  ) {}

  /**
   * 申请法币提现
   */
  async requestFiatWithdrawal(command: RequestFiatWithdrawalCommand): Promise<FiatWithdrawalResponseDTO> {
    const MAX_RETRIES = 3;
    let retries = 0;

    while (retries < MAX_RETRIES) {
      try {
        return await this.executeRequestFiatWithdrawal(command);
      } catch (error) {
        if (this.isOptimisticLockError(error)) {
          retries++;
          this.logger.warn(`[requestFiatWithdrawal] Optimistic lock conflict for ${command.accountSequence}, retry ${retries}/${MAX_RETRIES}`);
          if (retries >= MAX_RETRIES) {
            this.logger.error(`[requestFiatWithdrawal] Max retries exceeded for ${command.accountSequence}`);
            throw error;
          }
          await this.sleep(50 * retries);
        } else {
          throw error;
        }
      }
    }

    throw new Error('Unexpected: exited retry loop without result');
  }

  /**
   * 执行法币提现请求
   */
  private async executeRequestFiatWithdrawal(command: RequestFiatWithdrawalCommand): Promise<FiatWithdrawalResponseDTO> {
    const userId = BigInt(command.userId);
    const amount = Money.USDT(command.amount);

    // 从配置获取动态手续费
    const { fee: feeAmount, feeType, feeValue } = await this.feeConfigRepo.calculateFee(command.amount);
    const fee = Money.USDT(feeAmount);
    const totalRequired = amount;  // 法币提现：手续费从提现金额中扣除

    const feeDescription = feeType === FeeType.FIXED
      ? `固定 ${feeValue} 绿积分`
      : `${(feeValue * 100).toFixed(2)}%`;

    this.logger.log(`Processing fiat withdrawal request for user ${userId}: ${command.amount} 绿积分, fee: ${feeAmount} (${feeDescription})`);

    // 验证最小提现金额
    if (command.amount < this.MIN_WITHDRAWAL_AMOUNT) {
      throw new BadRequestException(`最小提现金额为 ${this.MIN_WITHDRAWAL_AMOUNT} 绿积分`);
    }

    // 优先按 accountSequence 查找，如果未找到则按 userId 查找
    let wallet = await this.walletRepo.findByAccountSequence(command.accountSequence);
    if (!wallet) {
      wallet = await this.walletRepo.findByUserId(userId);
    }
    if (!wallet) {
      throw new WalletNotFoundError(`accountSequence: ${command.accountSequence}`);
    }

    // 验证余额是否足够
    if (wallet.balances.usdt.available.lessThan(totalRequired)) {
      throw new BadRequestException(
        `余额不足: 需要 ${totalRequired.value} 绿积分, 当前可用 ${wallet.balances.usdt.available.value} 绿积分`,
      );
    }

    // 构建收款账户信息
    const paymentAccount: PaymentAccountInfo = {
      paymentMethod: command.paymentMethod,
      bankName: command.bankName,
      bankCardNo: command.bankCardNo,
      cardHolderName: command.cardHolderName,
      alipayAccount: command.alipayAccount,
      alipayRealName: command.alipayRealName,
      wechatAccount: command.wechatAccount,
      wechatRealName: command.wechatRealName,
    };

    // 创建法币提现订单
    const fiatWithdrawalOrder = FiatWithdrawalOrder.create({
      accountSequence: wallet.accountSequence,
      userId: UserId.create(userId),
      amount,
      fee,
      paymentAccount,
    });

    // 冻结用户余额
    wallet.freeze(totalRequired);
    await this.walletRepo.save(wallet);

    // 标记订单已冻结并提交审核
    fiatWithdrawalOrder.markAsFrozen();
    fiatWithdrawalOrder.submitForReview();
    const savedOrder = await this.fiatWithdrawalRepo.save(fiatWithdrawalOrder);

    // 记录流水 - 冻结
    const freezeEntry = LedgerEntry.create({
      accountSequence: wallet.accountSequence,
      userId: UserId.create(userId),
      entryType: LedgerEntryType.FREEZE,
      amount: Money.signed(-totalRequired.value, 'USDT'),
      balanceAfter: wallet.balances.usdt.available,
      refOrderId: savedOrder.orderNo,
      memo: `法币提现冻结: ${command.amount} 绿积分 (含手续费 ${feeAmount.toFixed(2)} 绿积分)`,
    });
    await this.ledgerRepo.save(freezeEntry);

    // 清除钱包缓存
    await this.walletCacheService.invalidateWallet(userId);

    this.logger.log(`Fiat withdrawal order created: ${savedOrder.orderNo}`);

    return {
      orderNo: savedOrder.orderNo,
      amount: savedOrder.amount.value,
      fee: savedOrder.fee.value,
      netAmount: savedOrder.netAmount.value,
      status: savedOrder.status,
      paymentMethod: savedOrder.paymentMethod,
    };
  }

  /**
   * 审核法币提现
   */
  async reviewFiatWithdrawal(command: ReviewFiatWithdrawalCommand): Promise<FiatWithdrawalListItemDTO> {
    const order = await this.fiatWithdrawalRepo.findByOrderNo(command.orderNo);
    if (!order) {
      throw new BadRequestException(`提现订单不存在: ${command.orderNo}`);
    }

    if (command.approved) {
      order.approve(command.reviewedBy, command.remark);
    } else {
      if (!command.remark) {
        throw new BadRequestException('驳回时必须填写原因');
      }
      order.reject(command.reviewedBy, command.remark);

      // 驳回时解冻资金
      if (order.needsUnfreeze()) {
        await this.unfreezeForOrder(order);
      }
    }

    const savedOrder = await this.fiatWithdrawalRepo.save(order);
    return this.toListItemDTO(savedOrder);
  }

  /**
   * 开始打款
   */
  async startPayment(command: StartPaymentCommand): Promise<FiatWithdrawalListItemDTO> {
    const order = await this.fiatWithdrawalRepo.findByOrderNo(command.orderNo);
    if (!order) {
      throw new BadRequestException(`提现订单不存在: ${command.orderNo}`);
    }

    order.startPayment(command.paidBy);
    const savedOrder = await this.fiatWithdrawalRepo.save(order);
    return this.toListItemDTO(savedOrder);
  }

  /**
   * 完成打款
   */
  async completePayment(command: CompletePaymentCommand): Promise<FiatWithdrawalListItemDTO> {
    const order = await this.fiatWithdrawalRepo.findByOrderNo(command.orderNo);
    if (!order) {
      throw new BadRequestException(`提现订单不存在: ${command.orderNo}`);
    }

    order.completePayment(command.paymentProof, command.remark);
    const savedOrder = await this.fiatWithdrawalRepo.save(order);

    // 扣除冻结余额并记录流水
    await this.deductFrozenForOrder(savedOrder);

    return this.toListItemDTO(savedOrder);
  }

  /**
   * 取消法币提现
   */
  async cancelFiatWithdrawal(orderNo: string, reason?: string): Promise<FiatWithdrawalListItemDTO> {
    const order = await this.fiatWithdrawalRepo.findByOrderNo(orderNo);
    if (!order) {
      throw new BadRequestException(`提现订单不存在: ${orderNo}`);
    }

    order.cancel(reason);

    // 取消时解冻资金
    if (order.needsUnfreeze()) {
      await this.unfreezeForOrder(order);
    }

    const savedOrder = await this.fiatWithdrawalRepo.save(order);
    return this.toListItemDTO(savedOrder);
  }

  /**
   * 获取用户的法币提现订单列表
   */
  async getFiatWithdrawals(accountSequence: string): Promise<FiatWithdrawalListItemDTO[]> {
    // 使用 accountSequence 查询法币提现订单（废弃 userId 查询）
    const orders = await this.fiatWithdrawalRepo.findByAccountSequence(accountSequence);
    return orders.map(order => this.toListItemDTO(order));
  }

  /**
   * 获取待审核的法币提现订单
   */
  async getPendingReviewOrders(): Promise<FiatWithdrawalListItemDTO[]> {
    const orders = await this.fiatWithdrawalRepo.findPendingReview();
    return orders.map(order => this.toListItemDTO(order));
  }

  /**
   * 获取待打款的法币提现订单
   */
  async getPendingPaymentOrders(): Promise<FiatWithdrawalListItemDTO[]> {
    const orders = await this.fiatWithdrawalRepo.findPendingPayment();
    return orders.map(order => this.toListItemDTO(order));
  }

  /**
   * 根据状态获取订单
   */
  async getOrdersByStatus(status: FiatWithdrawalStatus): Promise<FiatWithdrawalListItemDTO[]> {
    const orders = await this.fiatWithdrawalRepo.findByStatus(status);
    return orders.map(order => this.toListItemDTO(order));
  }

  /**
   * 解冻订单资金
   */
  private async unfreezeForOrder(order: FiatWithdrawalOrder): Promise<void> {
    const wallet = await this.walletRepo.findByAccountSequence(order.accountSequence);
    if (!wallet) {
      this.logger.error(`Wallet not found for unfreeze: ${order.accountSequence}`);
      return;
    }

    // 解冻余额
    wallet.unfreeze(order.amount);
    await this.walletRepo.save(wallet);

    // 记录流水
    const unfreezeEntry = LedgerEntry.create({
      accountSequence: wallet.accountSequence,
      userId: order.userId,
      entryType: LedgerEntryType.UNFREEZE,
      amount: Money.signed(order.amount.value, 'USDT'),
      balanceAfter: wallet.balances.usdt.available,
      refOrderId: order.orderNo,
      memo: `法币提现解冻: ${order.amount.value} 绿积分 (${order.status === FiatWithdrawalStatus.REJECTED ? '审核驳回' : '用户取消'})`,
    });
    await this.ledgerRepo.save(unfreezeEntry);

    // 清除缓存
    await this.walletCacheService.invalidateWallet(order.userId.value);
  }

  /**
   * 手续费归集账户序列号
   * S0000000006: 手续费归集账户 (user_id = -6)
   */
  private static readonly FEE_COLLECTION_ACCOUNT = 'S0000000006';
  private static readonly FEE_COLLECTION_USER_ID = BigInt(-6);

  /**
   * 扣除冻结余额（打款完成后）
   * 同时归集手续费到系统账户
   */
  private async deductFrozenForOrder(order: FiatWithdrawalOrder): Promise<void> {
    const wallet = await this.walletRepo.findByAccountSequence(order.accountSequence);
    if (!wallet) {
      this.logger.error(`Wallet not found for deduct frozen: ${order.accountSequence}`);
      return;
    }

    // 使用事务处理：用户钱包扣款 + 手续费归集
    await this.prisma.$transaction(async (tx) => {
      // 1. 扣除用户冻结余额
      const walletRecord = await tx.walletAccount.findUnique({
        where: { accountSequence: order.accountSequence },
      });

      if (!walletRecord) {
        throw new Error(`Wallet not found: ${order.accountSequence}`);
      }

      const totalAmount = new Decimal(order.amount.value);
      const currentFrozen = new Decimal(walletRecord.usdtFrozen.toString());
      const currentVersion = walletRecord.version;

      if (currentFrozen.lessThan(totalAmount)) {
        throw new Error(`Insufficient frozen balance: ${currentFrozen} < ${totalAmount}`);
      }

      const newFrozen = currentFrozen.minus(totalAmount);

      // 乐观锁更新
      const updateResult = await tx.walletAccount.updateMany({
        where: {
          id: walletRecord.id,
          version: currentVersion,
        },
        data: {
          usdtFrozen: newFrozen,
          version: currentVersion + 1,
          updatedAt: new Date(),
        },
      });

      if (updateResult.count === 0) {
        throw new OptimisticLockError(`Optimistic lock conflict for wallet ${walletRecord.id}`);
      }

      // 2. 记录用户提现流水
      await tx.ledgerEntry.create({
        data: {
          accountSequence: order.accountSequence,
          userId: order.userId.value,
          entryType: LedgerEntryType.FIAT_WITHDRAWAL,
          amount: new Decimal(order.netAmount.value).negated(),
          assetType: 'USDT',
          balanceAfter: walletRecord.usdtAvailable,
          refOrderId: order.orderNo,
          memo: `法币提现至${order.getPaymentMethodName()}: ${order.netAmount.value.toFixed(2)} 元人民币`,
          payloadJson: {
            paymentMethod: order.paymentMethod,
            paymentAccountDisplay: order.getPaymentAccountDisplay(),
            amount: order.amount.value,
            fee: order.fee.value,
            netAmount: order.netAmount.value,
          },
        },
      });

      // 3. 归集手续费到系统账户 S0000000006
      if (order.fee.value > 0) {
        const feeAccountSequence = FiatWithdrawalApplicationService.FEE_COLLECTION_ACCOUNT;
        const feeUserId = FiatWithdrawalApplicationService.FEE_COLLECTION_USER_ID;

        // 获取手续费账户
        const feeAccountRecord = await tx.walletAccount.findUnique({
          where: { accountSequence: feeAccountSequence },
        });

        if (!feeAccountRecord) {
          this.logger.error(`[FEE_COLLECTION] Fee collection account ${feeAccountSequence} not found!`);
          throw new Error(`Fee collection account ${feeAccountSequence} not found`);
        }

        const feeAmount = new Decimal(order.fee.value);
        const newFeeBalance = new Decimal(feeAccountRecord.usdtAvailable.toString()).plus(feeAmount);
        const feeAccountVersion = feeAccountRecord.version;

        // 更新手续费账户余额（乐观锁）
        const feeUpdateResult = await tx.walletAccount.updateMany({
          where: {
            id: feeAccountRecord.id,
            version: feeAccountVersion,
          },
          data: {
            usdtAvailable: newFeeBalance,
            version: feeAccountVersion + 1,
            updatedAt: new Date(),
          },
        });

        if (feeUpdateResult.count === 0) {
          throw new OptimisticLockError(`Optimistic lock conflict for fee account ${feeAccountRecord.id}`);
        }

        // 记录手续费归集流水
        await tx.ledgerEntry.create({
          data: {
            accountSequence: feeAccountSequence,
            userId: feeUserId,
            entryType: LedgerEntryType.FEE_COLLECTION,
            amount: feeAmount,
            assetType: 'USDT',
            balanceAfter: newFeeBalance,
            refOrderId: order.orderNo,
            memo: `法币提现手续费归集: ${order.fee.value} 绿积分`,
            payloadJson: {
              feeType: 'FIAT_WITHDRAWAL_FEE',
              sourceOrderNo: order.orderNo,
              collectedAt: new Date().toISOString(),
            },
          },
        });

        this.logger.log(`[FEE_COLLECTION] Fiat withdrawal fee collected: ${order.fee.value} USDT from order ${order.orderNo}`);
      }
    });

    // 清除缓存
    await this.walletCacheService.invalidateWallet(order.userId.value);
  }

  /**
   * 转换为列表项 DTO
   */
  private toListItemDTO(order: FiatWithdrawalOrder): FiatWithdrawalListItemDTO {
    return {
      orderNo: order.orderNo,
      accountSequence: order.accountSequence,
      userId: order.userId.value.toString(),
      amount: order.amount.value,
      fee: order.fee.value,
      netAmount: order.netAmount.value,
      paymentMethod: order.paymentMethod,
      paymentMethodName: order.getPaymentMethodName(),
      paymentAccountDisplay: order.getPaymentAccountDisplay(),
      status: order.status,
      reviewedBy: order.reviewedBy,
      reviewedAt: order.reviewedAt?.toISOString() ?? null,
      reviewRemark: order.reviewRemark,
      paidBy: order.paidBy,
      paidAt: order.paidAt?.toISOString() ?? null,
      frozenAt: order.frozenAt?.toISOString() ?? null,
      completedAt: order.completedAt?.toISOString() ?? null,
      createdAt: order.createdAt.toISOString(),
    };
  }

  private isOptimisticLockError(error: unknown): boolean {
    return error instanceof OptimisticLockError;
  }

  private sleep(ms: number): Promise<void> {
    return new Promise(resolve => setTimeout(resolve, ms));
  }
}
