/**
 * Synor IBC SDK Examples for C#
 *
 * Demonstrates Inter-Blockchain Communication operations:
 * - Chain and channel management
 * - Cross-chain token transfers
 * - Packet lifecycle handling
 * - Relayer operations
 * - Connection monitoring
 */

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Synor.Ibc;

namespace Synor.Examples;

public class IbcExample
{
    private readonly SynorIbc _ibc;

    public IbcExample(SynorIbc ibc)
    {
        _ibc = ibc;
    }

    public async Task RunChainsExample()
    {
        Console.WriteLine("=== Chain Information ===");

        // List connected chains
        var chains = await _ibc.Chains.ListAsync();
        Console.WriteLine($"Connected chains: {chains.Count}");
        foreach (var chain in chains.GetRange(0, Math.Min(chains.Count, 5)))
        {
            Console.WriteLine($"  {chain.ChainId}: {chain.Name} ({chain.Status})");
        }

        // Get specific chain info
        var cosmosHub = await _ibc.Chains.GetAsync("cosmoshub-4");
        Console.WriteLine($"\n{cosmosHub.Name}:");
        Console.WriteLine($"  Chain ID: {cosmosHub.ChainId}");
        Console.WriteLine($"  RPC endpoint: {cosmosHub.RpcEndpoint}");
        Console.WriteLine($"  Block height: {cosmosHub.LatestHeight}");
        Console.WriteLine($"  Active channels: {cosmosHub.ActiveChannels}");

        // Get chain clients
        var clients = await _ibc.Chains.GetClientsAsync("cosmoshub-4");
        Console.WriteLine($"\nIBC clients: {clients.Count}");
        foreach (var client in clients.GetRange(0, Math.Min(clients.Count, 3)))
        {
            Console.WriteLine($"  {client.ClientId}: {client.ChainId} ({client.ClientType})");
        }
        Console.WriteLine();
    }

    public async Task RunChannelsExample()
    {
        Console.WriteLine("=== Channel Management ===");

        // List channels
        var channels = await _ibc.Channels.ListAsync();
        Console.WriteLine($"IBC channels: {channels.Count}");
        foreach (var channel in channels.GetRange(0, Math.Min(channels.Count, 5)))
        {
            Console.WriteLine($"  {channel.ChannelId}: {channel.SourceChain} <-> {channel.DestChain} ({channel.State})");
        }

        // Get channel details
        var channelId = "channel-0";
        var channel = await _ibc.Channels.GetAsync(channelId);
        Console.WriteLine($"\nChannel {channelId}:");
        Console.WriteLine($"  State: {channel.State}");
        Console.WriteLine($"  Port: {channel.PortId}");
        Console.WriteLine($"  Counterparty: {channel.CounterpartyChannelId}");
        Console.WriteLine($"  Connection: {channel.ConnectionId}");
        Console.WriteLine($"  Ordering: {channel.Ordering}");
        Console.WriteLine($"  Version: {channel.Version}");

        // Create a new channel (4-step handshake)
        Console.WriteLine("\nInitiating channel creation...");
        var initResult = await _ibc.Channels.InitAsync(new ChannelInitRequest
        {
            SourceChain = "synor-mainnet",
            DestChain = "osmosis-1",
            PortId = "transfer",
            Version = "ics20-1"
        });
        Console.WriteLine($"  ChanOpenInit sent: {initResult.ChannelId}");

        // In production, the following steps happen through relayers:
        // ChanOpenTry -> ChanOpenAck -> ChanOpenConfirm

        // Get channel statistics
        var stats = await _ibc.Channels.GetStatsAsync(channelId);
        Console.WriteLine($"\nChannel statistics:");
        Console.WriteLine($"  Packets sent: {stats.PacketsSent}");
        Console.WriteLine($"  Packets received: {stats.PacketsReceived}");
        Console.WriteLine($"  Packets acknowledged: {stats.PacketsAcknowledged}");
        Console.WriteLine($"  Packets timed out: {stats.PacketsTimedOut}");
        Console.WriteLine();
    }

    public async Task RunTransferExample()
    {
        Console.WriteLine("=== Cross-Chain Transfers ===");

        // Get transfer routes
        Console.WriteLine("Available transfer routes:");
        var routes = await _ibc.Transfers.GetRoutesAsync("ATOM", "synor-mainnet");
        foreach (var route in routes)
        {
            Console.WriteLine($"  {route.SourceChain} -> {route.DestChain}: {route.ChannelId}");
            Console.WriteLine($"    Estimated time: {route.EstimatedTime}");
            Console.WriteLine($"    Fee: {route.Fee} {route.FeeAsset}");
        }

        // Initiate a transfer
        Console.WriteLine("\nInitiating transfer...");
        var transfer = await _ibc.Transfers.SendAsync(new TransferRequest
        {
            SourceChain = "cosmoshub-4",
            DestChain = "synor-mainnet",
            ChannelId = "channel-0",
            Asset = "uatom",
            Amount = "1000000", // 1 ATOM
            Sender = "cosmos1abc...",
            Receiver = "synor1xyz...",
            Timeout = TimeSpan.FromMinutes(30),
            Memo = "IBC transfer test"
        });

        Console.WriteLine($"Transfer initiated:");
        Console.WriteLine($"  Transfer ID: {transfer.TransferId}");
        Console.WriteLine($"  Sequence: {transfer.Sequence}");
        Console.WriteLine($"  Status: {transfer.Status}");

        // Track transfer status
        Console.WriteLine("\nTracking transfer...");
        var status = await _ibc.Transfers.GetStatusAsync(transfer.TransferId);
        Console.WriteLine($"  Current status: {status.Status}");
        Console.WriteLine($"  Source tx: {status.SourceTxHash}");
        if (!string.IsNullOrEmpty(status.DestTxHash))
        {
            Console.WriteLine($"  Dest tx: {status.DestTxHash}");
        }

        // Get transfer history
        var history = await _ibc.Transfers.GetHistoryAsync(new TransferHistoryFilter
        {
            Limit = 5
        });
        Console.WriteLine($"\nRecent transfers: {history.Count}");
        foreach (var tx in history)
        {
            Console.WriteLine($"  {tx.TransferId}: {tx.Amount} {tx.Asset} ({tx.Status})");
        }
        Console.WriteLine();
    }

    public async Task RunPacketExample()
    {
        Console.WriteLine("=== Packet Handling ===");

        // Get pending packets
        var pendingPackets = await _ibc.Packets.GetPendingAsync("channel-0");
        Console.WriteLine($"Pending packets: {pendingPackets.Count}");
        foreach (var packet in pendingPackets.GetRange(0, Math.Min(pendingPackets.Count, 5)))
        {
            Console.WriteLine($"  Seq {packet.Sequence}: {packet.SourcePort} -> {packet.DestPort}");
        }

        // Get packet details
        if (pendingPackets.Count > 0)
        {
            var packet = await _ibc.Packets.GetAsync("channel-0", pendingPackets[0].Sequence);
            Console.WriteLine($"\nPacket {packet.Sequence}:");
            Console.WriteLine($"  Source: {packet.SourcePort}/{packet.SourceChannel}");
            Console.WriteLine($"  Dest: {packet.DestPort}/{packet.DestChannel}");
            Console.WriteLine($"  Timeout height: {packet.TimeoutHeight}");
            Console.WriteLine($"  Timeout timestamp: {packet.TimeoutTimestamp}");
            Console.WriteLine($"  Data: {Convert.ToHexString(packet.Data)[..Math.Min(packet.Data.Length * 2, 64)]}...");
        }

        // Query packet commitments
        var commitments = await _ibc.Packets.GetCommitmentsAsync("channel-0");
        Console.WriteLine($"\nPacket commitments: {commitments.Count}");

        // Query unreceived packets
        var unreceived = await _ibc.Packets.GetUnreceivedAsync("channel-0", new ulong[] { 1, 2, 3, 4, 5 });
        Console.WriteLine($"Unreceived packets: {string.Join(", ", unreceived)}");

        // Query acknowledgements
        var acks = await _ibc.Packets.GetAcknowledgementsAsync("channel-0");
        Console.WriteLine($"Packet acknowledgements: {acks.Count}");
        Console.WriteLine();
    }

    public async Task RunRelayerExample()
    {
        Console.WriteLine("=== Relayer Operations ===");

        // Get relayer status
        var relayers = await _ibc.Relayer.ListAsync();
        Console.WriteLine($"Active relayers: {relayers.Count}");
        foreach (var relayer in relayers.GetRange(0, Math.Min(relayers.Count, 3)))
        {
            Console.WriteLine($"  {relayer.Address}: {relayer.PacketsRelayed} packets ({relayer.Status})");
        }

        // Register as a relayer
        Console.WriteLine("\nRegistering as relayer...");
        var registration = await _ibc.Relayer.RegisterAsync(new RelayerRegistration
        {
            Address = "synor1relayer...",
            Chains = new List<string> { "synor-mainnet", "cosmoshub-4", "osmosis-1" },
            Commission = 0.1m // 0.1%
        });
        Console.WriteLine($"  Registered: {registration.RelayerId}");

        // Start relaying
        Console.WriteLine("\nStarting packet relay...");
        var relayConfig = new RelayConfig
        {
            Channels = new List<string> { "channel-0", "channel-1" },
            BatchSize = 10,
            PollInterval = TimeSpan.FromSeconds(5)
        };

        // In production, this would run continuously
        var pendingCount = await _ibc.Relayer.GetPendingCountAsync(relayConfig.Channels);
        Console.WriteLine($"  Pending packets to relay: {pendingCount}");

        // Relay a batch
        var relayResult = await _ibc.Relayer.RelayBatchAsync("channel-0", 5);
        Console.WriteLine($"  Relayed: {relayResult.PacketsRelayed}");
        Console.WriteLine($"  Fees earned: {relayResult.FeesEarned}");

        // Get relayer earnings
        var earnings = await _ibc.Relayer.GetEarningsAsync("synor1relayer...");
        Console.WriteLine($"\nRelayer earnings:");
        Console.WriteLine($"  Total earned: {earnings.TotalEarned}");
        Console.WriteLine($"  Packets relayed: {earnings.PacketsRelayed}");
        Console.WriteLine($"  Success rate: {earnings.SuccessRate:F1}%");
        Console.WriteLine();
    }

    public async Task RunMonitoringExample()
    {
        Console.WriteLine("=== Connection Monitoring ===");

        // Get connection health
        var connections = await _ibc.Monitoring.GetConnectionsAsync();
        Console.WriteLine("Connection health:");
        foreach (var conn in connections)
        {
            var healthIcon = conn.Healthy ? "✓" : "✗";
            Console.WriteLine($"  [{healthIcon}] {conn.ConnectionId}: {conn.ChainA} <-> {conn.ChainB}");
            Console.WriteLine($"      Latency: {conn.Latency}ms, Uptime: {conn.Uptime:F1}%");
        }

        // Get channel metrics
        var metrics = await _ibc.Monitoring.GetChannelMetricsAsync("channel-0");
        Console.WriteLine($"\nChannel metrics:");
        Console.WriteLine($"  Throughput: {metrics.PacketsPerHour}/hour");
        Console.WriteLine($"  Avg latency: {metrics.AvgLatencyMs}ms");
        Console.WriteLine($"  Success rate: {metrics.SuccessRate:F1}%");
        Console.WriteLine($"  Volume 24h: {metrics.Volume24h}");

        // Subscribe to events (in production)
        Console.WriteLine("\nEvent subscription example:");
        Console.WriteLine("  Subscribing to packet events...");
        // await _ibc.Monitoring.SubscribeAsync("channel-0", (evt) => {
        //     Console.WriteLine($"  Event: {evt.Type} - {evt.Data}");
        // });

        // Get alerts
        var alerts = await _ibc.Monitoring.GetAlertsAsync();
        Console.WriteLine($"\nActive alerts: {alerts.Count}");
        foreach (var alert in alerts)
        {
            Console.WriteLine($"  [{alert.Severity}] {alert.Message}");
            Console.WriteLine($"    Channel: {alert.ChannelId}, Time: {alert.Timestamp}");
        }
        Console.WriteLine();
    }

    public static async Task Main(string[] args)
    {
        // Initialize client
        var apiKey = Environment.GetEnvironmentVariable("SYNOR_API_KEY") ?? "your-api-key";
        var config = new IbcConfig
        {
            ApiKey = apiKey,
            Endpoint = "https://ibc.synor.io/v1",
            Timeout = TimeSpan.FromSeconds(60),
            Retries = 3,
            Debug = false,
            DefaultTimeout = TimeSpan.FromMinutes(30)
        };

        var ibc = new SynorIbc(config);
        var example = new IbcExample(ibc);

        try
        {
            // Check service health
            var healthy = await ibc.HealthCheckAsync();
            Console.WriteLine($"Service healthy: {healthy}\n");

            // Run examples
            await example.RunChainsExample();
            await example.RunChannelsExample();
            await example.RunTransferExample();
            await example.RunPacketExample();
            await example.RunRelayerExample();
            await example.RunMonitoringExample();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error: {ex.Message}");
            Environment.Exit(1);
        }
    }
}
