/**
 * System Withdrawal Application Service
 *
 * 处理系统账户转出到用户账户的业务逻辑
 * - 支持从固定系统账户（总部、运营、积分股池等）转出
 * - 支持从区域账户（省区域、市区域）转出
 * - 记录双边流水（系统账户转出 + 用户账户转入）
 *
 * [2026-01-07] 更新：使用 Outbox Pattern 确保事件发布的原子性
 * - 事件写入 outbox_events 表与业务数据在同一个事务中
 * - 后台任务轮询 outbox 表发布事件到 Kafka
 * - 保证事件不丢失，即使 Kafka 暂时不可用
 */

import { Injectable, Logger, BadRequestException } from '@nestjs/common';
import { PrismaService } from '@/infrastructure/persistence/prisma/prisma.service';
import { IdentityClientService } from '@/infrastructure/external/identity/identity-client.service';
import { HotWalletCacheService } from '@/infrastructure/redis';
import { LedgerEntryType } from '@/domain/value-objects/ledger-entry-type.enum';
// [2026-01-07] 新增：使用 Outbox Pattern
import {
  OutboxRepository,
  OutboxEventData,
} from '@/infrastructure/persistence/repositories/outbox.repository';
import Decimal from 'decimal.js';

// 系统账户名称映射
const SYSTEM_ACCOUNT_NAMES: Record<string, string> = {
  'S0000000001': '总部储蓄',
  'S0000000002': '运营1',
  'S0000000003': '运营2',
  'S0000000004': '积分股池',
  'S0000000005': '分享权益池',
  'S0000000006': '手续费归集',
};

// 允许转出的系统账户白名单
const ALLOWED_WITHDRAWAL_ACCOUNTS = new Set([
  'S0000000001', // 总部账户
  'S0000000002', // 运营1
  'S0000000003', // 运营2
  'S0000000004', // 积分股池
  'S0000000005', // 分享权益池
  'S0000000006', // 手续费归集
]);

export interface SystemWithdrawalCommand {
  fromAccountSequence: string;  // 系统账户序列号
  toAccountSequence: string;    // 接收方充值ID
  amount: number;               // 转出金额
  memo?: string;                // 备注
  operatorId: string;           // 操作管理员ID
  operatorName?: string;        // 操作管理员姓名
}

export interface SystemWithdrawalResult {
  orderNo: string;
  fromAccountSequence: string;
  fromAccountName: string;
  toAccountSequence: string;
  toUserName: string | null;
  toAddress: string;
  amount: number;
  status: string;
}

@Injectable()
export class SystemWithdrawalApplicationService {
  private readonly logger = new Logger(SystemWithdrawalApplicationService.name);

  constructor(
    private readonly prisma: PrismaService,
    // [2026-01-07] 更新：使用 OutboxRepository 替代直接的 EventPublisher
    private readonly outboxRepository: OutboxRepository,
    private readonly identityClient: IdentityClientService,
    private readonly hotWalletCacheService: HotWalletCacheService,
  ) {}

  /**
   * 获取系统账户名称
   */
  getSystemAccountName(accountSequence: string): string {
    // 固定系统账户
    if (SYSTEM_ACCOUNT_NAMES[accountSequence]) {
      return SYSTEM_ACCOUNT_NAMES[accountSequence];
    }

    // 省区域账户: 9 + 省代码
    if (accountSequence.startsWith('9') && accountSequence.length === 7) {
      return `省区域(${accountSequence.substring(1)})`;
    }

    // 市区域账户: 8 + 市代码
    if (accountSequence.startsWith('8') && accountSequence.length === 7) {
      return `市区域(${accountSequence.substring(1)})`;
    }

    // 省团队账户: 7 + 省代码
    if (accountSequence.startsWith('7') && accountSequence.length === 7) {
      return `省团队(${accountSequence.substring(1)})`;
    }

    // 市团队账户: 6 + 市代码
    if (accountSequence.startsWith('6') && accountSequence.length === 7) {
      return `市团队(${accountSequence.substring(1)})`;
    }

    return `系统账户(${accountSequence})`;
  }

  /**
   * 检查账户是否允许转出
   */
  isWithdrawalAllowed(accountSequence: string): boolean {
    // 固定系统账户白名单
    if (ALLOWED_WITHDRAWAL_ACCOUNTS.has(accountSequence)) {
      return true;
    }

    // 区域/团队账户: 6=市团队, 7=省团队, 8=市区域, 9=省区域
    if (/^[6-9]\d{6}$/.test(accountSequence)) {
      return true;
    }

    return false;
  }

  /**
   * 发起系统账户转出
   */
  async requestSystemWithdrawal(command: SystemWithdrawalCommand): Promise<SystemWithdrawalResult> {
    this.logger.log(`[SYSTEM_WITHDRAWAL] 发起转出: ${command.fromAccountSequence} -> ${command.toAccountSequence}, 金额: ${command.amount}`);

    // 1. 验证转出账户是否在白名单中
    if (!this.isWithdrawalAllowed(command.fromAccountSequence)) {
      throw new BadRequestException(`账户 ${command.fromAccountSequence} 不允许转出`);
    }

    // 2. 获取系统账户名称
    const fromAccountName = this.getSystemAccountName(command.fromAccountSequence);

    // 3. 验证接收方账户（必须是 D 开头的用户账户）
    if (!command.toAccountSequence.startsWith('D')) {
      throw new BadRequestException('接收方必须是用户账户（D开头）');
    }

    // 4. 获取接收方用户信息和区块链地址
    const toUserInfo = await this.identityClient.getUserInfoByAccountSequence(command.toAccountSequence);
    if (!toUserInfo) {
      throw new BadRequestException(`未找到接收方用户: ${command.toAccountSequence}`);
    }

    // 5. 检查热钱包余额
    const hotWalletCheck = await this.hotWalletCacheService.checkSufficientBalance(
      'KAVA',
      new Decimal(command.amount),
    );
    if (!hotWalletCheck.sufficient) {
      this.logger.warn(`[SYSTEM_WITHDRAWAL] 热钱包余额不足: ${hotWalletCheck.error}`);
      throw new BadRequestException(hotWalletCheck.error || '财务系统审计中，请稍后再试');
    }

    // 6. 在事务中执行
    const result = await this.prisma.$transaction(async (tx) => {
      // 6.1 查找系统账户并验证余额
      const systemWallet = await tx.walletAccount.findUnique({
        where: { accountSequence: command.fromAccountSequence },
      });

      if (!systemWallet) {
        throw new BadRequestException(`系统账户不存在: ${command.fromAccountSequence}`);
      }

      let currentAvailable = new Decimal(systemWallet.usdtAvailable.toString());
      const settleableAmount = new Decimal(systemWallet.settleableUsdt?.toString() || '0');
      const withdrawAmount = new Decimal(command.amount);

      // 6.1.1 如果是区域/团队账户且有待结算余额，先自动结算
      // 6=市团队, 7=省团队, 8=市区域, 9=省区域 — 这些账户的奖励都进 settleableUsdt
      const isRegionAccount = /^[6-9]/.test(command.fromAccountSequence);
      if (isRegionAccount && settleableAmount.greaterThan(0)) {
        this.logger.log(
          `[SYSTEM_WITHDRAWAL] 区域账户 ${command.fromAccountSequence} 自动结算: ` +
          `settleableUsdt=${settleableAmount.toFixed(2)} → usdtAvailable`
        );

        // 结算：settleableUsdt → usdtAvailable
        const newAvailable = currentAvailable.plus(settleableAmount);
        await tx.walletAccount.update({
          where: { id: systemWallet.id },
          data: {
            usdtAvailable: newAvailable,
            settleableUsdt: new Decimal(0),
            updatedAt: new Date(),
          },
        });

        // 记录结算流水（审计用）
        await tx.ledgerEntry.create({
          data: {
            accountSequence: command.fromAccountSequence,
            userId: systemWallet.userId,
            entryType: LedgerEntryType.REWARD_SETTLED,
            amount: settleableAmount,
            assetType: 'USDT',
            balanceAfter: newAvailable,
            memo: `系统账户自动结算: 待结算 ${settleableAmount.toFixed(2)} 绿积分转入可用余额（划转前自动执行）`,
            payloadJson: {
              settledAmount: settleableAmount.toFixed(2),
              previousAvailable: currentAvailable.toFixed(2),
              newAvailable: newAvailable.toFixed(2),
              trigger: 'SYSTEM_WITHDRAWAL_AUTO_SETTLE',
            },
          },
        });

        // 更新本地变量
        currentAvailable = newAvailable;
        this.logger.log(
          `[SYSTEM_WITHDRAWAL] 自动结算完成: 可用余额 ${currentAvailable.toFixed(2)} 绿积分`
        );
      }

      // 6.1.2 验证可用余额是否足够
      if (currentAvailable.lessThan(withdrawAmount)) {
        throw new BadRequestException(
          `余额不足: 当前可用 ${currentAvailable.toFixed(2)} 绿积分, 需要 ${withdrawAmount.toFixed(2)} 绿积分`
        );
      }

      // 6.2 生成订单号
      const orderNo = this.generateOrderNo();

      // 6.3 扣减系统账户余额
      const newBalance = currentAvailable.minus(withdrawAmount);
      await tx.walletAccount.update({
        where: { id: systemWallet.id },
        data: {
          usdtAvailable: newBalance,
          updatedAt: new Date(),
        },
      });

      // 6.4 记录系统账户转出流水
      // [2026-01-07] 更新：memo 包含完整的接收方和操作员信息
      const memoDetails = [
        `转账至 ${command.toAccountSequence}`,
        toUserInfo.realName ? `(${toUserInfo.realName})` : null,
        `地址: ${toUserInfo.walletAddress.slice(0, 10)}...${toUserInfo.walletAddress.slice(-8)}`,
        `操作员: ${command.operatorName || command.operatorId}`,
        command.memo ? `备注: ${command.memo}` : null,
      ].filter(Boolean).join(' | ');

      await tx.ledgerEntry.create({
        data: {
          accountSequence: command.fromAccountSequence,
          userId: systemWallet.userId,
          entryType: LedgerEntryType.SYSTEM_TRANSFER_OUT,
          amount: withdrawAmount.negated(),
          assetType: 'USDT',
          balanceAfter: newBalance,
          refOrderId: orderNo,
          memo: memoDetails,
          payloadJson: {
            toAccountSequence: command.toAccountSequence,
            toUserId: toUserInfo.userId,
            toUserName: toUserInfo.realName,
            toAddress: toUserInfo.walletAddress,
            operatorId: command.operatorId,
            operatorName: command.operatorName,
          },
        },
      });

      // 6.5 创建转出订单
      const order = await tx.systemWithdrawalOrder.create({
        data: {
          orderNo,
          fromAccountSequence: command.fromAccountSequence,
          fromAccountName,
          toAccountSequence: command.toAccountSequence,
          toUserId: BigInt(toUserInfo.userId),
          toUserName: toUserInfo.realName,
          toAddress: toUserInfo.walletAddress,
          amount: withdrawAmount,
          chainType: 'KAVA',
          status: 'FROZEN',
          operatorId: command.operatorId,
          operatorName: command.operatorName,
          memo: command.memo,
          frozenAt: new Date(),
        },
      });

      // 6.6 [2026-01-07] 新增：在事务中写入 Outbox 事件
      // 使用 Outbox Pattern 确保事件发布的原子性
      const outboxEvent: OutboxEventData = {
        eventType: 'wallet.system-withdrawal.requested',
        topic: 'wallet.system-withdrawals',
        key: orderNo,
        aggregateId: orderNo,
        aggregateType: 'SystemWithdrawalOrder',
        payload: {
          eventId: `${Date.now()}-${Math.random().toString(36).substring(2, 9)}`,
          eventType: 'wallet.system-withdrawal.requested',
          occurredAt: new Date().toISOString(),
          payload: {
            orderNo,
            fromAccountSequence: command.fromAccountSequence,
            fromAccountName,
            toAccountSequence: command.toAccountSequence,
            toAddress: toUserInfo.walletAddress,
            amount: command.amount.toString(),
            chainType: 'KAVA',
          },
        },
      };

      await this.outboxRepository.saveInTransaction(tx, [outboxEvent]);

      this.logger.log(`[SYSTEM_WITHDRAWAL] 转出订单和 Outbox 事件已写入事务: ${orderNo}`);

      return {
        orderNo: order.orderNo,
        fromAccountSequence: command.fromAccountSequence,
        fromAccountName,
        toAccountSequence: command.toAccountSequence,
        toUserName: toUserInfo.realName,
        toAddress: toUserInfo.walletAddress,
        amount: command.amount,
        status: order.status,
      };
    });

    // 7. [2026-01-07] 更新：事件已在事务中写入 Outbox 表
    // 后台 OutboxPublisher 服务会自动轮询并发布到 Kafka
    this.logger.log(`[SYSTEM_WITHDRAWAL] 转出订单创建成功: ${result.orderNo}, 事件将由 OutboxPublisher 发布`);

    return result;
  }

  /**
   * 处理转账确认（由 blockchain-service 事件触发）
   */
  async handleWithdrawalConfirmed(orderNo: string, txHash: string): Promise<void> {
    this.logger.log(`[SYSTEM_WITHDRAWAL] 处理转账确认: orderNo=${orderNo}, txHash=${txHash}`);

    await this.prisma.$transaction(async (tx) => {
      // 1. 查找订单
      const order = await tx.systemWithdrawalOrder.findUnique({
        where: { orderNo },
      });

      if (!order) {
        throw new Error(`订单不存在: ${orderNo}`);
      }

      if (order.status === 'CONFIRMED') {
        this.logger.warn(`[SYSTEM_WITHDRAWAL] 订单已确认，跳过: ${orderNo}`);
        return;
      }

      // 2. 更新订单状态
      await tx.systemWithdrawalOrder.update({
        where: { orderNo },
        data: {
          status: 'CONFIRMED',
          txHash,
          confirmedAt: new Date(),
        },
      });

      // 3. 查找接收方钱包（如果不存在则创建）
      let toWallet = await tx.walletAccount.findUnique({
        where: { accountSequence: order.toAccountSequence },
      });

      if (!toWallet) {
        this.logger.log(`[SYSTEM_WITHDRAWAL] 接收方钱包不存在，自动创建: ${order.toAccountSequence}`);
        toWallet = await tx.walletAccount.upsert({
          where: { accountSequence: order.toAccountSequence },
          create: {
            accountSequence: order.toAccountSequence,
            userId: order.toUserId,
            usdtAvailable: new Decimal(0),
            usdtFrozen: new Decimal(0),
            dstAvailable: new Decimal(0),
            dstFrozen: new Decimal(0),
            bnbAvailable: new Decimal(0),
            bnbFrozen: new Decimal(0),
            ogAvailable: new Decimal(0),
            ogFrozen: new Decimal(0),
            rwadAvailable: new Decimal(0),
            rwadFrozen: new Decimal(0),
            hashpower: new Decimal(0),
            pendingUsdt: new Decimal(0),
            pendingHashpower: new Decimal(0),
            settleableUsdt: new Decimal(0),
            settleableHashpower: new Decimal(0),
            settledTotalUsdt: new Decimal(0),
            settledTotalHashpower: new Decimal(0),
            expiredTotalUsdt: new Decimal(0),
            expiredTotalHashpower: new Decimal(0),
            status: 'ACTIVE',
            hasPlanted: false,
            version: 0,
          },
          update: {},
        });
      }

      // 4. 增加接收方余额
      const transferAmount = new Decimal(order.amount.toString());
      const toCurrentBalance = new Decimal(toWallet.usdtAvailable.toString());
      const toNewBalance = toCurrentBalance.plus(transferAmount);

      await tx.walletAccount.update({
        where: { id: toWallet.id },
        data: {
          usdtAvailable: toNewBalance,
          updatedAt: new Date(),
        },
      });

      // 5. 记录接收方转入流水
      await tx.ledgerEntry.create({
        data: {
          accountSequence: order.toAccountSequence,
          userId: order.toUserId,
          entryType: LedgerEntryType.SYSTEM_TRANSFER_IN,
          amount: transferAmount,
          assetType: 'USDT',
          balanceAfter: toNewBalance,
          refOrderId: orderNo,
          refTxHash: txHash,
          memo: `来自${order.fromAccountName}的转入${order.memo ? ` - ${order.memo}` : ''}`,
          payloadJson: {
            fromAccountSequence: order.fromAccountSequence,
            fromAccountName: order.fromAccountName,
          },
        },
      });

      this.logger.log(`[SYSTEM_WITHDRAWAL] 转账确认完成: ${orderNo}, 接收方余额: ${toNewBalance}`);
    });
  }

  /**
   * 处理转账失败（由 blockchain-service 事件触发）
   */
  async handleWithdrawalFailed(orderNo: string, error: string): Promise<void> {
    this.logger.log(`[SYSTEM_WITHDRAWAL] 处理转账失败: orderNo=${orderNo}, error=${error}`);

    await this.prisma.$transaction(async (tx) => {
      // 1. 查找订单
      const order = await tx.systemWithdrawalOrder.findUnique({
        where: { orderNo },
      });

      if (!order) {
        throw new Error(`订单不存在: ${orderNo}`);
      }

      if (order.status === 'FAILED' || order.status === 'CONFIRMED') {
        this.logger.warn(`[SYSTEM_WITHDRAWAL] 订单状态已终结，跳过: ${orderNo}, status=${order.status}`);
        return;
      }

      // 2. 更新订单状态
      await tx.systemWithdrawalOrder.update({
        where: { orderNo },
        data: {
          status: 'FAILED',
          errorMessage: error,
        },
      });

      // 3. 退还系统账户余额
      const systemWallet = await tx.walletAccount.findUnique({
        where: { accountSequence: order.fromAccountSequence },
      });

      if (systemWallet) {
        const refundAmount = new Decimal(order.amount.toString());
        const currentBalance = new Decimal(systemWallet.usdtAvailable.toString());
        const newBalance = currentBalance.plus(refundAmount);

        await tx.walletAccount.update({
          where: { id: systemWallet.id },
          data: {
            usdtAvailable: newBalance,
            updatedAt: new Date(),
          },
        });

        // 记录退款流水
        await tx.ledgerEntry.create({
          data: {
            accountSequence: order.fromAccountSequence,
            userId: systemWallet.userId,
            entryType: LedgerEntryType.UNFREEZE,
            amount: refundAmount,
            assetType: 'USDT',
            balanceAfter: newBalance,
            refOrderId: orderNo,
            memo: `转账失败退款: ${error}`,
            payloadJson: {
              toAccountSequence: order.toAccountSequence,
              error,
            },
          },
        });
      }

      this.logger.log(`[SYSTEM_WITHDRAWAL] 转账失败处理完成: ${orderNo}`);
    });
  }

  /**
   * 查询转出订单列表
   */
  async getSystemWithdrawalOrders(params: {
    fromAccountSequence?: string;
    toAccountSequence?: string;
    status?: string;
    page?: number;
    pageSize?: number;
  }): Promise<{
    orders: any[];
    total: number;
    page: number;
    pageSize: number;
  }> {
    const page = params.page || 1;
    const pageSize = params.pageSize || 20;
    const skip = (page - 1) * pageSize;

    const where: any = {};
    if (params.fromAccountSequence) {
      where.fromAccountSequence = params.fromAccountSequence;
    }
    if (params.toAccountSequence) {
      where.toAccountSequence = params.toAccountSequence;
    }
    if (params.status) {
      where.status = params.status;
    }

    const [orders, total] = await Promise.all([
      this.prisma.systemWithdrawalOrder.findMany({
        where,
        orderBy: { createdAt: 'desc' },
        skip,
        take: pageSize,
      }),
      this.prisma.systemWithdrawalOrder.count({ where }),
    ]);

    return {
      orders: orders.map((o) => ({
        ...o,
        id: o.id.toString(),
        toUserId: o.toUserId.toString(),
        amount: o.amount.toString(),
      })),
      total,
      page,
      pageSize,
    };
  }

  /**
   * 获取可转出的系统账户列表
   * [2026-01-07] 更新：S0000000006 手续费归集账户余额为0时，从提现订单表统计历史手续费
   */
  async getWithdrawableSystemAccounts(): Promise<{
    accountSequence: string;
    accountName: string;
    balance: string;
  }[]> {
    const accounts: string[] = [
      'S0000000001', // 总部账户
      'S0000000002', // 运营1
      'S0000000003', // 运营2
      'S0000000004', // 积分股池
      'S0000000005', // 分享权益池
      'S0000000006', // 手续费归集
    ];

    // 查询固定系统账户
    const wallets = await this.prisma.walletAccount.findMany({
      where: {
        accountSequence: { in: accounts },
      },
    });

    // 查询区域账户（省区域 9 开头，市区域 8 开头）
    const regionWallets = await this.prisma.walletAccount.findMany({
      where: {
        OR: [
          { accountSequence: { startsWith: '9' } },
          { accountSequence: { startsWith: '8' } },
        ],
      },
    });

    const allWallets = [...wallets, ...regionWallets];

    // [2026-01-07] 兼容：检查 S0000000006 手续费归集账户
    // 如果账户不存在或余额为0，从提现订单表统计历史手续费
    const feeAccountSequence = 'S0000000006';
    const feeWallet = allWallets.find(w => w.accountSequence === feeAccountSequence);
    const feeBalance = feeWallet ? new Decimal(feeWallet.usdtAvailable.toString()) : new Decimal(0);

    let adjustedFeeBalance = feeBalance;
    if (feeBalance.isZero()) {
      this.logger.log('[getWithdrawableSystemAccounts] S0000000006 余额为0，从提现订单表统计历史手续费');
      const fallbackBalance = await this.calculateFeeCollectionFromOrders();
      adjustedFeeBalance = new Decimal(fallbackBalance);
      this.logger.log(`[getWithdrawableSystemAccounts] 历史手续费总额: ${adjustedFeeBalance.toFixed(2)}`);
    }

    // 构建返回结果
    const result = allWallets.map((w) => {
      // 对于手续费归集账户，使用调整后的余额
      if (w.accountSequence === feeAccountSequence) {
        return {
          accountSequence: w.accountSequence,
          accountName: this.getSystemAccountName(w.accountSequence),
          balance: adjustedFeeBalance.toString(),
        };
      }
      return {
        accountSequence: w.accountSequence,
        accountName: this.getSystemAccountName(w.accountSequence),
        balance: w.usdtAvailable.toString(),
      };
    });

    // [2026-01-07] 兼容：如果 S0000000006 账户不存在于数据库，但有历史手续费，也要显示
    if (!feeWallet && !adjustedFeeBalance.isZero()) {
      result.push({
        accountSequence: feeAccountSequence,
        accountName: this.getSystemAccountName(feeAccountSequence),
        balance: adjustedFeeBalance.toString(),
      });
    }

    return result;
  }

  /**
   * 从提现订单表统计历史手续费总额
   * [2026-01-07] 新增：用于 S0000000006 账户余额为0时的兼容
   * 回滚方式：删除此方法
   */
  private async calculateFeeCollectionFromOrders(): Promise<number> {
    // 1. 统计区块链提现订单手续费 (CONFIRMED 状态)
    const withdrawalStats = await this.prisma.withdrawalOrder.aggregate({
      where: { status: 'CONFIRMED' },
      _sum: { fee: true },
    });

    // 2. 统计法币提现订单手续费 (COMPLETED 状态)
    const fiatStats = await this.prisma.fiatWithdrawalOrder.aggregate({
      where: { status: 'COMPLETED' },
      _sum: { fee: true },
    });

    const withdrawalFeeAmount = Number(withdrawalStats._sum.fee) || 0;
    const fiatFeeAmount = Number(fiatStats._sum.fee) || 0;

    return withdrawalFeeAmount + fiatFeeAmount;
  }

  /**
   * 生成订单号
   */
  private generateOrderNo(): string {
    const timestamp = Date.now().toString(36).toUpperCase();
    const random = Math.random().toString(36).substring(2, 8).toUpperCase();
    return `SWD${timestamp}${random}`;
  }
}
