import 'dart:async';

import 'package:reown_appkit/modal/i_appkit_modal_impl.dart';
import 'package:reown_appkit/reown_appkit.dart';

import 'evm_recharge.dart';
import '../../data/models/asset/recharge_order.dart';

/// 使用 Reown AppKit 连接钱包并向订单收款地址发起转账（与 Web `useWalletConnectDeposit` 对齐）。
class WalletConnectRechargeHelper {
  WalletConnectRechargeHelper._();

  static const _erc20Abi = '''
[{"constant":false,"inputs":[{"name":"_to","type":"address"},{"name":"_value","type":"uint256"}],"name":"transfer","outputs":[{"name":"","type":"bool"}],"type":"function"}]
''';

  static BigInt _parseUnits(String amount, int decimals) {
    final s = amount.trim();
    if (s.isEmpty) {
      throw FormatException('empty amount');
    }
    var normalized = s.replaceAll(',', '');
    final neg = normalized.startsWith('-');
    if (neg) {
      normalized = normalized.substring(1);
    }
    final parts = normalized.split('.');
    final intPart = parts[0].isEmpty ? '0' : parts[0];
    var frac = parts.length > 1 ? parts[1] : '';
    if (frac.length > decimals) {
      frac = frac.substring(0, decimals);
    } else {
      frac = frac.padRight(decimals, '0');
    }
    final combined = intPart + frac;
    var bi = BigInt.parse(combined);
    if (neg) {
      bi = -bi;
    }
    return bi;
  }

  static Future<void> ensureConnected(IReownAppKitModal modal) async {
    if (modal.isConnected) {
      return;
    }
    final completer = Completer<void>();
    void onConnect(ModalConnect _) {
      if (!completer.isCompleted) {
        completer.complete();
      }
    }

    modal.onModalConnect.subscribe(onConnect);
    try {
      // 与「先 await openModalView 再 await connect」不同：用户关掉弹窗未连接时，
      // openModalView 会结束而 onConnect 永不触发，会导致外层 loading 卡死到超时。
      final modalClosed = modal.openModalView();
      await Future.any<void>([
        completer.future,
        modalClosed,
      ]).timeout(
        const Duration(minutes: 3),
        onTimeout: () {
          throw TimeoutException('WalletConnect 连接超时');
        },
      );
      if (!modal.isConnected) {
        throw StateError('WalletConnect 已取消或未连接');
      }
    } finally {
      modal.onModalConnect.unsubscribe(onConnect);
    }
  }

  static Future<void> ensureEvmChain(
    IReownAppKitModal modal,
    int chainId,
  ) async {
    final net = ReownAppKitModalNetworks.getNetworkInfo(
      'eip155',
      chainIdToCaip2(chainId),
    );
    if (net == null) {
      throw StateError('不支持的链 chainId=$chainId');
    }
    await modal.selectChain(net, switchChain: true);
  }

  /// 返回交易 hash（0x…）。
  static Future<String> connectAndPay({
    required IReownAppKitModal appKitModal,
    required RechargeFlatNetworkOption network,
    required RechargeOrderDetail order,
  }) async {
    final chainId = resolveEvmChainId(network.protocol, network.networkName);
    if (chainId == null) {
      throw StateError('当前网络不支持 WalletConnect，请使用钱包手动转账');
    }

    await ensureConnected(appKitModal);
    await ensureEvmChain(appKitModal, chainId);

    final session = appKitModal.session;
    if (session == null) {
      throw StateError('会话无效');
    }
    final fromRaw = session.getAddress('eip155');
    if (fromRaw == null || fromRaw.isEmpty) {
      throw StateError('未获取到钱包地址');
    }
    final from = EthereumAddress.fromHex(fromRaw);
    final to = EthereumAddress.fromHex(order.rechargeAddress.trim());
    final caip2 = chainIdToCaip2(chainId);
    final topic = session.topic;
    final amountStr = order.amount.trim();

    if (network.hasTokenContract) {
      final token = EthereumAddress.fromHex(network.contractAddress.trim());
      final decimals = erc20DecimalsForChain(chainId);
      final amountWei = _parseUnits(amountStr, decimals);
      final abi = ContractAbi.fromJson(_erc20Abi, 'ERC20');
      final deployed = DeployedContract(abi, token);
      final hash = await appKitModal.requestWriteContract(
        topic: topic,
        chainId: caip2,
        deployedContract: deployed,
        functionName: 'transfer',
        transaction: Transaction(from: from),
        parameters: [to, amountWei],
      );
      return hash.toString();
    } else {
      final valueWei = _parseUnits(amountStr, 18);
      final trx = Transaction(
        from: from,
        to: to,
        value: EtherAmount.fromBigInt(EtherUnit.wei, valueWei),
      );
      final hash = await appKitModal.request(
        topic: topic,
        chainId: caip2,
        request: SessionRequestParams(
          method: MethodsConstants.ethSendTransaction,
          params: [trx.toJson()],
        ),
      );
      return hash.toString();
    }
  }
}
