import 'dart:convert';

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

import '../config/app_config.dart';
import '../../data/models/asset/recharge_order.dart';
import 'tron_fullnode_client.dart';
import 'tron_recharge.dart';
import 'wallet_connect_recharge_helper.dart';

/// 使用 Reown AppKit 的 Tron 命名空间签名 + FullNode 广播（与 Web `useWalletConnectTronDeposit.ts` 对齐）。
class WalletConnectTronRecharge {
  WalletConnectTronRecharge._();

  static Map<String, dynamic> _deepMap(Object raw) {
    return jsonDecode(jsonEncode(raw)) as Map<String, dynamic>;
  }

  static Map<String, dynamic> _prepareUnsigned(Map<String, dynamic> tx) {
    final o = _deepMap(tx);
    o.remove('signature');
    final rd = o['raw_data'];
    if (rd is Map) {
      final contracts = rd['contract'];
      if (contracts is List) {
        for (final c in contracts) {
          if (c is Map && !c.containsKey('Permission_id')) {
            c['Permission_id'] = 0;
          }
        }
      }
    }
    return o;
  }

  static Map<String, dynamic> _cloneWithoutTxId(Map<String, dynamic> tx) {
    final c = _deepMap(tx);
    c.remove('txID');
    return c;
  }

  /// triggersmartcontract 完整响应的多种形态（与官方示例及常见钱包兼容）。
  static List<Map<String, dynamic>> _triggerEnvelopesForWallet(
    Map<String, dynamic> full,
  ) {
    final out = <Map<String, dynamic>>[_deepMap(full)];
    final inner = full['transaction'];
    if (inner is Map) {
      final innerMap = Map<String, dynamic>.from(inner);
      final preparedInner = _prepareUnsigned(innerMap);
      final wrapped = _deepMap(full);
      wrapped['transaction'] = preparedInner;
      out.add(wrapped);
      final noId = _deepMap(full);
      noId['transaction'] = _cloneWithoutTxId(preparedInner);
      out.add(noId);
    }
    return out;
  }

  static String _formatSignFailure(Object e) {
    if (e is ReownSignError) {
      final d = e.data;
      final extra = (d != null && d.isNotEmpty) ? ' data=$d' : '';
      return 'ReownSignError(code=${e.code}, message=${e.message})$extra';
    }
    return e.toString();
  }

  static Map<String, dynamic> _normalizeSigned(dynamic raw) {
    dynamic cur = raw;
    if (cur is String) {
      try {
        cur = jsonDecode(cur) as Object?;
      } catch (_) {
        throw StateError('钱包返回的签名格式无效');
      }
    }
    if (cur is! Map) {
      throw StateError('钱包未返回签名数据');
    }
    final m = Map<String, dynamic>.from(cur);
    if (m['result'] != null && m['result'] is Map) {
      return _normalizeSigned(m['result']);
    }
    if (m['signature'] is List &&
        (m['signature'] as List).isNotEmpty &&
        m['raw_data'] is Map) {
      return m;
    }
    for (final k in ['transaction', 'signedTransaction', 'tx']) {
      final inner = m[k];
      if (inner is Map) {
        try {
          return _normalizeSigned(inner);
        } catch (_) {
          // 尝试下一包裹字段
        }
      }
    }
    throw StateError('钱包未返回有效签名（signature）');
  }

  static bool _tronSessionUsesSignV1(ReownAppKitModalSession? session) {
    final v = session?.sessionProperties['tron_method_version'];
    return v == 'v1';
  }

  static String _tronSessionAccountString(
    ReownAppKitModalSession session,
    String base58,
  ) {
    final raw = session.getAccounts(namespace: 'tron') ?? [];
    for (final a in raw) {
      if (parseTronCaip10Address(a) == base58) {
        return a;
      }
    }
    return tronMainnetCaip10Account(base58);
  }

  static Future<Map<String, dynamic>> _requestTronSignTransaction({
    required IReownAppKitModal modal,
    required String topic,
    required ReownAppKitModalSession session,
    required String fromBase58,
    required Map<String, dynamic> unsigned,
    Map<String, dynamic>? triggerSmartContractBody,
  }) async {
    final prepared = _prepareUnsigned(unsigned);
    final noTxId = _cloneWithoutTxId(prepared);
    final sessionAcct = _tronSessionAccountString(session, fromBase58);
    final useV1 = _tronSessionUsesSignV1(session);

    final rawVariants = <Map<String, dynamic>>[];

    // 顺序：优先 Reown 官方示例（完整 triggersmartcontract 响应 + Base58 地址），
    // 其次 CAIP-10 账户字符串；内层仅 tx 时先扁平 transaction 再嵌套；全部 Map 试完后再试 JSON-RPC 风格的 [params]。
    if (triggerSmartContractBody != null) {
      for (final env in _triggerEnvelopesForWallet(triggerSmartContractBody)) {
        rawVariants.add({'address': fromBase58, 'transaction': env});
        rawVariants.add({'address': sessionAcct, 'transaction': env});
      }
    }

    if (useV1) {
      rawVariants.add({'address': fromBase58, 'transaction': prepared});
      rawVariants.add({'address': sessionAcct, 'transaction': prepared});
      rawVariants.add({
        'address': fromBase58,
        'transaction': {'transaction': prepared},
      });
      rawVariants.add({'transaction': prepared});
      rawVariants.add({'address': fromBase58, 'transaction': noTxId});
      rawVariants.add({'address': sessionAcct, 'transaction': noTxId});
      rawVariants.add({'transaction': noTxId});
    } else {
      rawVariants.add({'address': fromBase58, 'transaction': prepared});
      rawVariants.add({'address': sessionAcct, 'transaction': prepared});
      rawVariants.add({
        'address': fromBase58,
        'transaction': {'transaction': prepared},
      });
      rawVariants.add({
        'address': sessionAcct,
        'transaction': {'transaction': prepared},
      });
      rawVariants.add({'transaction': prepared});
      rawVariants.add({'transaction': {'transaction': prepared}});
      rawVariants.add({'address': fromBase58, 'transaction': noTxId});
      rawVariants.add({'address': sessionAcct, 'transaction': noTxId});
      rawVariants.add({
        'address': fromBase58,
        'transaction': {'transaction': noTxId},
      });
      rawVariants.add({
        'address': sessionAcct,
        'transaction': {'transaction': noTxId},
      });
      rawVariants.add({'transaction': noTxId});
      rawVariants.add({'transaction': {'transaction': noTxId}});
    }

    final variants = <dynamic>[
      ...rawVariants,
      ...rawVariants.map((m) => [m]),
    ];

    Object? lastErr;
    for (var i = 0; i < variants.length; i++) {
      try {
        final out = await modal.request(
          topic: topic,
          chainId: kTronMainnetCaip2,
          request: SessionRequestParams(
            method: 'tron_signTransaction',
            params: variants[i],
          ),
        );
        return _normalizeSigned(out);
      } catch (e) {
        lastErr = e;
      }
    }
    final err = lastErr;
    if (err == null) {
      throw StateError('tron_signTransaction 失败：未知错误');
    }
    throw StateError(
      'tron_signTransaction 失败（已尝试多种参数格式）。最后错误：${_formatSignFailure(err)}',
    );
  }

  /// 检查当前会话是否含 `tron_signTransaction`（不抛异常，仅返回布尔值）。
  static bool _sessionHasTronSign(ReownAppKitModalSession? session) {
    final ns = session?.namespaces;
    if (ns == null || ns.isEmpty) {
      return false;
    }
    final methods = NamespaceUtils.getNamespacesMethodsForChainId(
      chainId: kTronMainnetCaip2,
      namespaces: ns,
    );
    return methods.contains('tron_signTransaction');
  }

  static Future<void> _ensureTronSession(IReownAppKitModal modal) async {
    await WalletConnectRechargeHelper.ensureConnected(modal);

    // 旧会话（在 optionalNamespaces 修复前握手建立）可能不含 tron 签名方法，需强制重连。
    var addr = modal.session?.getAddress('tron');
    final needsReconnect = addr == null ||
        addr.isEmpty ||
        !_sessionHasTronSign(modal.session);
    if (needsReconnect) {
      await modal.disconnect(disconnectAllSessions: true);
      await WalletConnectRechargeHelper.ensureConnected(modal);
      addr = modal.session?.getAddress('tron');
    }
    if (addr == null || !addr.startsWith('T')) {
      throw StateError('请使用支持波场（Tron）的钱包连接后重试');
    }
    if (!_sessionHasTronSign(modal.session)) {
      throw StateError(
        '钱包未授权 tron_signTransaction，请在钱包端确认 Tron 命名空间后重试',
      );
    }
  }

  static Future<void> _ensureTronChain(IReownAppKitModal modal) async {
    final net =
        ReownAppKitModalNetworks.getNetworkInfo('tron', kTronMainnetCaip2);
    if (net == null) {
      throw StateError('App 未注册 Tron 网络');
    }
    await modal.selectChain(net, switchChain: true);
  }

  /// 返回 Tron 交易 txid（非 0x 以太坊 hash）。
  static Future<String> connectAndPayTron({
    required IReownAppKitModal appKitModal,
    required RechargeFlatNetworkOption network,
    required RechargeOrderDetail order,
  }) async {
    if (!order.isPendingPayment) {
      throw StateError('订单状态不可支付');
    }
    if (!isTronDepositNetwork(network.protocol, network.networkName)) {
      throw StateError('当前网络不支持波场 WalletConnect');
    }

    await _ensureTronSession(appKitModal);
    await _ensureTronChain(appKitModal);

    final session = appKitModal.session;
    if (session == null) {
      throw StateError('会话无效');
    }
    final topic = session.topic;
    if (topic == null || topic.isEmpty) {
      throw StateError('会话无效');
    }
    final from = session.getAddress('tron');
    if (from == null || !from.startsWith('T')) {
      throw StateError('未获取到波场钱包地址');
    }

    final to = order.rechargeAddress.trim();
    if (!to.startsWith('T')) {
      throw StateError('收款地址不是有效的波场地址');
    }

    final chainNet =
        ReownAppKitModalNetworks.getNetworkInfo('tron', kTronMainnetCaip2);
    if (chainNet == null) {
      throw StateError('Tron 网络未配置');
    }
    var rpc = chainNet.rpcUrl.trim();
    if (rpc.isEmpty) {
      rpc = AppConfig.tronFullHost;
    }

    final amountStr = order.amount.trim();
    var contract = network.contractAddress.trim();
    if (contract.isEmpty &&
        (isTronRechargeUsdtSymbol(network.coinName) ||
            isTronRechargeUsdtSymbol(order.coinName))) {
      contract = kTrc20UsdtOfficialMainnet;
    }

    final Map<String, dynamic> unsigned;
    final Map<String, dynamic>? triggerBody;
    if (contract.isNotEmpty) {
      final minUnits = BigInt.parse(
        trc20AmountToMinUnits(amountStr, kTrc20UsdtDecimals),
      );
      final paramHex = tronTransferTrc20ParameterHex(to, minUnits);
      triggerBody = await TronFullNodeClient.triggerSmartContract(
        rpcBase: rpc,
        ownerAddressBase58: from,
        contractAddressBase58: contract,
        functionSelector: 'transfer(address,uint256)',
        parameterHex: paramHex,
      );
      final inner = triggerBody['transaction'];
      if (inner is! Map) {
        throw StateError('TRC20 构造响应缺少 transaction');
      }
      unsigned = Map<String, dynamic>.from(inner);
    } else {
      triggerBody = null;
      final sun = trxToSunAmount(amountStr);
      unsigned = await TronFullNodeClient.createTrxTransaction(
        rpcBase: rpc,
        ownerAddressBase58: from,
        toAddressBase58: to,
        amountSun: sun,
      );
    }

    final signed = await _requestTronSignTransaction(
      modal: appKitModal,
      topic: topic,
      session: session,
      fromBase58: from,
      unsigned: unsigned,
      triggerSmartContractBody: triggerBody,
    );

    return TronFullNodeClient.broadcastTransaction(
      rpcBase: rpc,
      signed: signed,
    );
  }
}
