/**
 * 一次性修复脚本：补录内部转账入账
 *
 * ⚠️  警告：此脚本涉及资金操作，请务必仔细核对！
 *
 * 用于修复因接收方钱包未创建导致入账失败的内部转账。
 *
 * 执行前必须确认：
 * 1. 订单号正确
 * 2. 订单状态是 CONFIRMED（链上已完成）
 * 3. 接收方确实没有收到这笔转账
 * 4. 数据库中没有对应的 TRANSFER_IN 流水
 *
 * 安全机制：
 * 1. DRY_RUN 模式：默认只检查不执行，需要手动改为 false 才会真正执行
 * 2. 幂等性：检查 refOrderId + accountSequence + entryType 是否已存在
 * 3. 事务性：所有操作在同一个数据库事务中
 * 4. 乐观锁：使用 version 字段防止并发修改
 * 5. 审计追踪：payloadJson.dataFix=true 标记为修复操作
 *
 * 使用方法：
 *   在 wallet-service 容器内执行：
 *   npx ts-node scripts/fix-missing-transfer-in.ts
 *
 * 环境变量要求：
 *   - DATABASE_URL: 数据库连接字符串
 */

import { PrismaClient } from '@prisma/client';
import Decimal from 'decimal.js';

// ========== 配置 ==========
// 只需提供订单号，其他信息自动从数据库获取
const ORDER_NO = 'WD1767599904858VG01WF';

// ⚠️ 安全开关：设为 true 时只检查不执行，设为 false 才会真正修复
const DRY_RUN = true;
// ==========================

function log(level: 'INFO' | 'WARN' | 'ERROR' | 'DEBUG', message: string, data?: unknown) {
  const timestamp = new Date().toISOString();
  const prefix = `[${timestamp}] [${level}]`;
  if (data !== undefined) {
    console.log(`${prefix} ${message}`, JSON.stringify(data, null, 2));
  } else {
    console.log(`${prefix} ${message}`);
  }
}

async function main() {
  log('INFO', '========================================');
  log('INFO', '内部转账入账修复脚本');
  log('INFO', '========================================');
  log('INFO', `订单号: ${ORDER_NO}`);
  log('INFO', `模式: ${DRY_RUN ? '🔍 DRY_RUN (只检查不执行)' : '⚡ LIVE (真正执行)'}`);
  log('INFO', '');

  if (DRY_RUN) {
    log('WARN', '⚠️  DRY_RUN 模式：以下操作不会真正执行');
    log('WARN', '⚠️  确认无误后，将 DRY_RUN 改为 false 再次执行');
    log('INFO', '');
  }

  const prisma = new PrismaClient({
    log: ['warn', 'error'],
  });

  try {
    await prisma.$transaction(async (tx) => {
      // ==================== Step 1: 查询订单信息 ====================
      log('INFO', '[Step 1/7] 查询订单信息...');
      const order = await tx.withdrawalOrder.findUnique({
        where: { orderNo: ORDER_NO },
      });

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

      log('DEBUG', '订单原始数据:', {
        id: order.id,
        orderNo: order.orderNo,
        status: order.status,
        isInternalTransfer: order.isInternalTransfer,
        accountSequence: order.accountSequence,
        userId: order.userId.toString(),
        toAccountSequence: order.toAccountSequence,
        toUserId: order.toUserId?.toString(),
        amount: order.amount.toString(),
        fee: order.fee.toString(),
        txHash: order.txHash,
        confirmedAt: order.confirmedAt?.toISOString(),
        createdAt: order.createdAt.toISOString(),
      });

      // ==================== Step 2: 验证订单状态 ====================
      log('INFO', '[Step 2/7] 验证订单状态...');

      if (order.status !== 'CONFIRMED') {
        throw new Error(`❌ 订单状态不是 CONFIRMED，当前状态: ${order.status}`);
      }
      log('INFO', `      ✓ 订单状态: CONFIRMED`);

      if (!order.isInternalTransfer) {
        throw new Error(`❌ 订单不是内部转账，isInternalTransfer=${order.isInternalTransfer}`);
      }
      log('INFO', `      ✓ 订单类型: 内部转账`);

      if (!order.toAccountSequence) {
        throw new Error(`❌ 订单缺少接收方账号 toAccountSequence`);
      }
      if (!order.toUserId) {
        throw new Error(`❌ 订单缺少接收方用户ID toUserId`);
      }
      log('INFO', `      ✓ 接收方信息完整`);

      if (!order.txHash) {
        throw new Error(`❌ 订单缺少交易哈希 txHash，链上交易可能未完成`);
      }
      log('INFO', `      ✓ 链上交易已完成: ${order.txHash}`);

      const toAccountSequence = order.toAccountSequence;
      const toUserId = order.toUserId;
      const transferAmount = new Decimal(order.amount.toString());

      log('INFO', '');
      log('INFO', '📋 订单摘要:');
      log('INFO', `      订单号: ${order.orderNo}`);
      log('INFO', `      转出方: ${order.accountSequence} (userId=${order.userId})`);
      log('INFO', `      接收方: ${toAccountSequence} (userId=${toUserId})`);
      log('INFO', `      金额: ${transferAmount.toString()} USDT`);
      log('INFO', `      手续费: ${order.fee.toString()} USDT`);
      log('INFO', `      TxHash: ${order.txHash}`);
      log('INFO', `      确认时间: ${order.confirmedAt?.toISOString() || 'N/A'}`);
      log('INFO', '');

      // ==================== Step 3: 检查转出方流水 ====================
      log('INFO', '[Step 3/7] 检查转出方 TRANSFER_OUT 流水...');
      const transferOutEntry = await tx.ledgerEntry.findFirst({
        where: {
          refOrderId: ORDER_NO,
          accountSequence: order.accountSequence,
          entryType: 'TRANSFER_OUT',
        },
      });

      if (!transferOutEntry) {
        log('WARN', `      ⚠️  转出方没有 TRANSFER_OUT 流水！这可能表示整个转账都没有正常处理`);
        log('WARN', `      请先确认转出方是否已扣款`);
      } else {
        log('INFO', `      ✓ 转出方 TRANSFER_OUT 流水存在 (id=${transferOutEntry.id})`);
        log('DEBUG', '转出方流水:', {
          id: transferOutEntry.id,
          amount: transferOutEntry.amount.toString(),
          balanceAfter: transferOutEntry.balanceAfter?.toString() ?? 'null',
          createdAt: transferOutEntry.createdAt.toISOString(),
        });
      }

      // ==================== Step 4: 幂等性检查 ====================
      log('INFO', '[Step 4/7] 幂等性检查 - 接收方 TRANSFER_IN 流水...');
      const existingTransferIn = await tx.ledgerEntry.findFirst({
        where: {
          refOrderId: ORDER_NO,
          accountSequence: toAccountSequence,
          entryType: 'TRANSFER_IN',
        },
      });

      if (existingTransferIn) {
        log('ERROR', `      ❌ TRANSFER_IN 流水已存在！`);
        log('ERROR', '流水详情:', {
          id: existingTransferIn.id,
          amount: existingTransferIn.amount.toString(),
          balanceAfter: existingTransferIn.balanceAfter?.toString() ?? 'null',
          createdAt: existingTransferIn.createdAt.toISOString(),
        });
        log('ERROR', '');
        log('ERROR', '========================================');
        log('ERROR', '❌ 中止：接收方已有入账流水，不能重复入账！');
        log('ERROR', '========================================');
        return;
      }
      log('INFO', `      ✓ 未找到 TRANSFER_IN 流水，可以安全入账`);

      // ==================== Step 5: 查找接收方钱包 ====================
      log('INFO', '[Step 5/7] 查找接收方钱包...');
      let wallet = await tx.walletAccount.findUnique({
        where: { accountSequence: toAccountSequence },
      });

      if (!wallet) {
        wallet = await tx.walletAccount.findUnique({
          where: { userId: toUserId },
        });
      }

      if (wallet) {
        log('INFO', `      ✓ 钱包已存在`);
        log('DEBUG', '钱包信息:', {
          id: wallet.id,
          accountSequence: wallet.accountSequence,
          userId: wallet.userId.toString(),
          usdtAvailable: wallet.usdtAvailable.toString(),
          usdtFrozen: wallet.usdtFrozen.toString(),
          version: wallet.version,
          createdAt: wallet.createdAt.toISOString(),
        });
      } else {
        log('WARN', `      ⚠️  钱包不存在，需要创建`);
      }

      // ==================== Step 6: 计算新余额 ====================
      log('INFO', '[Step 6/7] 计算新余额...');
      const currentBalance = wallet ? new Decimal(wallet.usdtAvailable.toString()) : new Decimal(0);
      const newBalance = currentBalance.add(transferAmount);
      const currentVersion = wallet?.version ?? 0;

      log('INFO', `      当前余额: ${currentBalance.toString()} USDT`);
      log('INFO', `      转账金额: +${transferAmount.toString()} USDT`);
      log('INFO', `      新余额: ${newBalance.toString()} USDT`);
      log('INFO', '');

      // ==================== DRY_RUN 检查 ====================
      if (DRY_RUN) {
        log('INFO', '========================================');
        log('INFO', '🔍 DRY_RUN 模式 - 检查完成');
        log('INFO', '========================================');
        log('INFO', '');
        log('INFO', '以上检查全部通过，可以安全执行修复。');
        log('INFO', '');
        log('INFO', '将要执行的操作:');
        if (!wallet) {
          log('INFO', `  1. 创建钱包: ${toAccountSequence} (userId=${toUserId})`);
          log('INFO', `  2. 设置余额: ${newBalance.toString()} USDT`);
        } else {
          log('INFO', `  1. 更新钱包余额: ${currentBalance.toString()} -> ${newBalance.toString()} USDT`);
          log('INFO', `  2. 更新版本号: ${currentVersion} -> ${currentVersion + 1}`);
        }
        log('INFO', `  3. 创建 TRANSFER_IN 流水记录`);
        log('INFO', '');
        log('INFO', '确认无误后，请将 DRY_RUN 改为 false 再次执行。');
        return;
      }

      // ==================== Step 7: 执行修复 ====================
      log('INFO', '[Step 7/7] 执行修复...');

      // 7a. 创建或更新钱包
      if (!wallet) {
        log('INFO', '      创建钱包...');
        wallet = await tx.walletAccount.create({
          data: {
            accountSequence: toAccountSequence,
            userId: toUserId,
            usdtAvailable: newBalance, // 直接设置为转账金额
            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: 1,
          },
        });
        log('INFO', `      ✓ 钱包创建成功 (id=${wallet.id}, balance=${newBalance.toString()})`);
      } else {
        log('INFO', '      更新钱包余额...');
        const updateResult = await tx.walletAccount.updateMany({
          where: {
            id: wallet.id,
            version: currentVersion,
          },
          data: {
            usdtAvailable: newBalance,
            version: currentVersion + 1,
            updatedAt: new Date(),
          },
        });

        if (updateResult.count === 0) {
          throw new Error('❌ 乐观锁冲突：钱包数据已被其他操作修改，请重试');
        }
        log('INFO', `      ✓ 余额更新成功 (version: ${currentVersion} -> ${currentVersion + 1})`);
      }

      // 7b. 创建流水记录
      log('INFO', '      创建流水记录...');
      const entry = await tx.ledgerEntry.create({
        data: {
          accountSequence: toAccountSequence,
          userId: toUserId,
          entryType: 'TRANSFER_IN',
          amount: transferAmount,
          assetType: 'USDT',
          balanceAfter: newBalance,
          refOrderId: ORDER_NO,
          refTxHash: order.txHash,
          memo: `来自 ${order.accountSequence} 的转账（数据修复）`,
          payloadJson: {
            fromAccountSequence: order.accountSequence,
            fromUserId: order.userId.toString(),
            originalOrderNo: ORDER_NO,
            dataFix: true,
            fixedAt: new Date().toISOString(),
            fixReason: 'Receiver wallet not existed when transfer confirmed',
            scriptVersion: '1.0.0',
          },
        },
      });
      log('INFO', `      ✓ 流水记录创建成功 (id=${entry.id})`);

      // ==================== 完成 ====================
      log('INFO', '');
      log('INFO', '========================================');
      log('INFO', '✅ 修复成功!');
      log('INFO', '========================================');
      log('INFO', `接收方: ${toAccountSequence}`);
      log('INFO', `入账金额: ${transferAmount.toString()} USDT`);
      log('INFO', `新余额: ${newBalance.toString()} USDT`);
      log('INFO', `流水ID: ${entry.id}`);
      log('INFO', '');
      log('INFO', '验证命令:');
      log('INFO', `  SELECT account_sequence, usdt_available, version FROM wallet_accounts WHERE account_sequence = '${toAccountSequence}';`);
      log('INFO', `  SELECT id, entry_type, amount, balance_after, ref_order_id, created_at FROM wallet_ledger_entries WHERE ref_order_id = '${ORDER_NO}';`);
    });

  } catch (error) {
    log('ERROR', '');
    log('ERROR', '========================================');
    log('ERROR', '❌ 修复失败');
    log('ERROR', '========================================');
    if (error instanceof Error) {
      log('ERROR', `错误信息: ${error.message}`);
      log('DEBUG', `错误堆栈: ${error.stack}`);
    } else {
      log('ERROR', '未知错误:', error);
    }
    process.exit(1);
  } finally {
    await prisma.$disconnect();
  }
}

main();
