/// Synor IBC SDK Examples for Flutter/Dart
///
/// Demonstrates Inter-Blockchain Communication operations:
/// - Cross-chain token transfers
/// - Channel management
/// - Packet handling
/// - Relayer operations
library;

import 'dart:io';
import 'package:synor_ibc/synor_ibc.dart';

Future<void> main() async {
  // Initialize client
  final config = IbcConfig(
    apiKey: Platform.environment['SYNOR_API_KEY'] ?? 'your-api-key',
    endpoint: 'https://ibc.synor.io/v1',
    timeout: const Duration(seconds: 30),
    retries: 3,
    debug: false,
    defaultNetwork: Network.mainnet,
  );

  final ibc = SynorIbc(config);

  try {
    // Check service health
    final healthy = await ibc.healthCheck();
    print('Service healthy: $healthy\n');

    // Run examples
    await chainsExample(ibc);
    await channelsExample(ibc);
    await transferExample(ibc);
    await packetExample(ibc);
    await relayerExample(ibc);
    await connectionExample(ibc);
  } finally {
    await ibc.close();
  }
}

Future<void> chainsExample(SynorIbc ibc) async {
  print('=== Connected Chains ===');

  // Get all connected chains
  final chains = await ibc.chains.list();
  print('Connected chains: ${chains.length}');

  for (final chain in chains) {
    print('  ${chain.chainId}:');
    print('    Name: ${chain.name}');
    print('    Status: ${chain.status}');
    print('    Block height: ${chain.latestHeight}');
    print('    Channels: ${chain.channelCount}');
  }

  // Get specific chain info
  final cosmos = await ibc.chains.get('cosmoshub-4');
  print('\nCosmos Hub details:');
  print('  RPC: ${cosmos.rpcEndpoint}');
  print('  Rest: ${cosmos.restEndpoint}');
  print('  Native denom: ${cosmos.nativeDenom}');
  print('  Prefix: ${cosmos.bech32Prefix}');

  // Get supported assets on a chain
  final assets = await ibc.chains.getAssets('cosmoshub-4');
  print('\nSupported assets on Cosmos Hub:');
  for (final asset in assets.take(5)) {
    print('  ${asset.symbol}: ${asset.denom}');
    print('    Origin: ${asset.originChain}');
    print('    Decimals: ${asset.decimals}');
  }

  // Get chain paths (routes)
  final paths = await ibc.chains.getPaths('synor-1', 'cosmoshub-4');
  print('\nPaths from Synor to Cosmos Hub:');
  for (final path in paths) {
    print('  ${path.sourceChannel} -> ${path.destChannel}');
    print('    Hops: ${path.hops}');
    print('    Avg time: ${path.avgTransferTime}s');
  }

  print('');
}

Future<void> channelsExample(SynorIbc ibc) async {
  print('=== Channel Management ===');

  // List all channels
  final channels = await ibc.channels.list();
  print('Total channels: ${channels.length}');

  // Filter by state
  final openChannels =
      channels.where((c) => c.state == ChannelState.open).toList();
  print('Open channels: ${openChannels.length}');

  for (final channel in openChannels.take(3)) {
    print('\n  Channel ${channel.channelId}:');
    print('    Port: ${channel.portId}');
    print('    Counterparty: ${channel.counterpartyChannelId} on ${channel.counterpartyChainId}');
    print('    Ordering: ${channel.ordering}');
    print('    Version: ${channel.version}');
    print('    State: ${channel.state}');
  }

  // Get specific channel
  final channel = await ibc.channels.get('channel-0');
  print('\nChannel-0 details:');
  print('  Connection: ${channel.connectionId}');
  print('  Counterparty port: ${channel.counterpartyPortId}');

  // Get channel statistics
  final stats = await ibc.channels.getStats('channel-0');
  print('\nChannel-0 statistics:');
  print('  Total packets sent: ${stats.packetsSent}');
  print('  Total packets received: ${stats.packetsReceived}');
  print('  Pending packets: ${stats.pendingPackets}');
  print('  Success rate: ${stats.successRate}%');
  print('  Avg relay time: ${stats.avgRelayTime}s');

  // Get channel capacity
  final capacity = await ibc.channels.getCapacity('channel-0');
  print('\nChannel-0 capacity:');
  print('  Max throughput: ${capacity.maxPacketsPerBlock} packets/block');
  print('  Current utilization: ${capacity.utilization}%');

  print('');
}

Future<void> transferExample(SynorIbc ibc) async {
  print('=== Cross-Chain Transfers ===');

  // Estimate transfer fee
  final estimate = await ibc.transfers.estimateFee(FeeEstimateRequest(
    sourceChain: 'synor-1',
    destChain: 'cosmoshub-4',
    denom: 'usyn',
    amount: '1000000', // 1 SYN (6 decimals)
  ));

  print('Transfer fee estimate:');
  print('  Gas: ${estimate.gas}');
  print('  Fee: ${estimate.fee} ${estimate.feeDenom}');
  print('  Timeout: ${estimate.timeout}s');

  // Initiate a transfer
  print('\nInitiating transfer...');
  final transfer = await ibc.transfers.send(TransferRequest(
    sourceChain: 'synor-1',
    destChain: 'cosmoshub-4',
    channel: 'channel-0',
    sender: 'synor1abc...', // Your address
    receiver: 'cosmos1xyz...', // Recipient address
    denom: 'usyn',
    amount: '1000000', // 1 SYN
    memo: 'Cross-chain transfer example',
    timeoutHeight: 0, // Use timestamp instead
    timeoutTimestamp: DateTime.now().add(const Duration(minutes: 10)).millisecondsSinceEpoch,
  ));

  print('Transfer initiated:');
  print('  TX Hash: ${transfer.txHash}');
  print('  Sequence: ${transfer.sequence}');
  print('  Status: ${transfer.status}');

  // Track transfer status
  print('\nTracking transfer...');
  final status = await ibc.transfers.getStatus(transfer.txHash);
  print('Current status: ${status.state}');
  print('  Source confirmed: ${status.sourceConfirmed}');
  print('  Relayed: ${status.relayed}');
  print('  Dest confirmed: ${status.destConfirmed}');

  // Get transfer history
  final history = await ibc.transfers.getHistory('synor1abc...', limit: 5);
  print('\nTransfer history (last 5):');
  for (final tx in history) {
    final direction = tx.sender == 'synor1abc...' ? 'OUT' : 'IN';
    print('  $direction ${tx.amount} ${tx.denom} (${tx.status})');
  }

  // Get pending transfers
  final pending = await ibc.transfers.getPending('synor1abc...');
  print('\nPending transfers: ${pending.length}');

  print('');
}

Future<void> packetExample(SynorIbc ibc) async {
  print('=== Packet Handling ===');

  // Get pending packets
  final packets = await ibc.packets.getPending('channel-0');
  print('Pending packets on channel-0: ${packets.length}');

  for (final packet in packets.take(3)) {
    print('\n  Packet ${packet.sequence}:');
    print('    Source: ${packet.sourcePort}/${packet.sourceChannel}');
    print('    Dest: ${packet.destPort}/${packet.destChannel}');
    print('    State: ${packet.state}');
    print('    Data size: ${packet.data.length} bytes');
    print('    Timeout height: ${packet.timeoutHeight}');
    print('    Timeout timestamp: ${packet.timeoutTimestamp}');
  }

  // Get packet by sequence
  final packet = await ibc.packets.get('channel-0', 1);
  print('\nPacket details:');
  print('  Commitment: ${packet.commitment}');
  print('  Receipt: ${packet.receipt}');
  print('  Acknowledgement: ${packet.acknowledgement}');

  // Get packet receipts
  final receipts = await ibc.packets.getReceipts('channel-0', [1, 2, 3]);
  print('\nPacket receipts:');
  for (final entry in receipts.entries) {
    final status = entry.value ? 'received' : 'not received';
    print('  Sequence ${entry.key}: $status');
  }

  // Get timed out packets
  final timedOut = await ibc.packets.getTimedOut('channel-0');
  print('\nTimed out packets: ${timedOut.length}');
  for (final p in timedOut) {
    print('  Sequence ${p.sequence}: timeout at ${p.timeoutTimestamp}');
  }

  // Get unreceived packets
  final unreceived = await ibc.packets.getUnreceived('channel-0');
  final unreceivedStr = unreceived.isEmpty ? 'none' : unreceived.join(', ');
  print('\nUnreceived packet sequences: $unreceivedStr');

  // Get unacknowledged packets
  final unacked = await ibc.packets.getUnacknowledged('channel-0');
  final unackedStr = unacked.isEmpty ? 'none' : unacked.join(', ');
  print('Unacknowledged packet sequences: $unackedStr');

  print('');
}

Future<void> relayerExample(SynorIbc ibc) async {
  print('=== Relayer Operations ===');

  // Get active relayers
  final relayers = await ibc.relayers.list();
  print('Active relayers: ${relayers.length}');

  for (final relayer in relayers.take(3)) {
    print('\n  ${relayer.address}:');
    print('    Chains: ${relayer.chains.join(", ")}');
    print('    Packets relayed: ${relayer.packetsRelayed}');
    print('    Success rate: ${relayer.successRate}%');
    print('    Avg latency: ${relayer.avgLatency}ms');
    print('    Fee rate: ${relayer.feeRate}%');
  }

  // Get relayer statistics
  final stats = await ibc.relayers.getStats();
  print('\nGlobal relayer statistics:');
  print('  Total relayers: ${stats.totalRelayers}');
  print('  Active relayers: ${stats.activeRelayers}');
  print('  Packets relayed (24h): ${stats.packetsRelayed24h}');
  print('  Total fees earned: ${stats.totalFeesEarned}');

  // Register as a relayer
  print('\nRegistering as relayer...');
  final registration = await ibc.relayers.register(RelayerRegistration(
    chains: ['synor-1', 'cosmoshub-4'],
    feeRate: 0.1, // 0.1% fee
    minPacketSize: 0,
    maxPacketSize: 1000000,
  ));
  print('Registered with address: ${registration.relayerAddress}');

  // Start relaying (in background)
  print('\nStarting relay service...');
  final relaySession = await ibc.relayers.startRelay(RelayConfig(
    channels: ['channel-0'],
    autoAck: true,
    batchSize: 10,
    pollInterval: 5000,
  ));
  print('Relay session started: ${relaySession.sessionId}');

  // Get relay queue
  final queue = await ibc.relayers.getQueue('channel-0');
  print('\nRelay queue for channel-0: ${queue.length} packets');

  // Manually relay a packet
  if (queue.isNotEmpty) {
    print('\nRelaying packet...');
    final relayResult = await ibc.relayers.relayPacket(queue.first.sequence, 'channel-0');
    print('Relay result: ${relayResult.status}');
    print('  TX Hash: ${relayResult.txHash}');
    print('  Fee earned: ${relayResult.feeEarned}');
  }

  // Stop relay session
  await ibc.relayers.stopRelay(relaySession.sessionId);
  print('\nRelay session stopped');

  print('');
}

Future<void> connectionExample(SynorIbc ibc) async {
  print('=== Connection Information ===');

  // List connections
  final connections = await ibc.connections.list();
  print('Total connections: ${connections.length}');

  for (final conn in connections.take(3)) {
    print('\n  ${conn.connectionId}:');
    print('    Client: ${conn.clientId}');
    print('    Counterparty: ${conn.counterpartyConnectionId}');
    print('    State: ${conn.state}');
    print('    Versions: ${conn.versions.join(", ")}');
  }

  // Get connection details
  final connection = await ibc.connections.get('connection-0');
  print('\nConnection-0 details:');
  print('  Delay period: ${connection.delayPeriod}ns');
  print('  Counterparty client: ${connection.counterpartyClientId}');
  print('  Counterparty prefix: ${connection.counterpartyPrefix}');

  // Get client state
  final client = await ibc.clients.get(connection.clientId);
  print('\nClient state:');
  print('  Chain ID: ${client.chainId}');
  print('  Trust level: ${client.trustLevel}');
  print('  Trusting period: ${client.trustingPeriod}');
  print('  Unbonding period: ${client.unbondingPeriod}');
  print('  Latest height: ${client.latestHeight}');
  print('  Frozen: ${client.frozen}');

  // Get consensus state
  final consensus = await ibc.clients.getConsensusState(
    connection.clientId,
    client.latestHeight,
  );
  print('\nConsensus state at height ${client.latestHeight}:');
  print('  Timestamp: ${consensus.timestamp}');
  final rootPreview = consensus.root.length > 20
      ? consensus.root.substring(0, 20)
      : consensus.root;
  print('  Root: $rootPreview...');
  final validatorsPreview = consensus.nextValidatorsHash.length > 20
      ? consensus.nextValidatorsHash.substring(0, 20)
      : consensus.nextValidatorsHash;
  print('  Next validators hash: $validatorsPreview...');

  print('');
}
