/**
 * Synor Crypto SDK Examples for C#
 *
 * Demonstrates quantum-resistant cryptographic operations:
 * - Hybrid Ed25519 + Dilithium3 signatures
 * - BIP-39 mnemonic generation and validation
 * - Post-quantum algorithms (Falcon, SPHINCS+)
 * - Key derivation functions
 */

using System;
using System.Text;
using System.Threading.Tasks;
using Synor.Crypto;

namespace Synor.Examples;

public class CryptoExample
{
    private readonly SynorCrypto _crypto;

    public CryptoExample(SynorCrypto crypto)
    {
        _crypto = crypto;
    }

    public async Task RunMnemonicExample()
    {
        Console.WriteLine("=== Mnemonic Operations ===");

        // Generate a 24-word mnemonic (256-bit entropy)
        var mnemonic = await _crypto.Mnemonic.GenerateAsync(24);
        Console.WriteLine($"Generated mnemonic: {mnemonic.Phrase}");
        Console.WriteLine($"Word count: {mnemonic.WordCount}");

        // Validate a mnemonic
        var validation = await _crypto.Mnemonic.ValidateAsync(mnemonic.Phrase);
        Console.WriteLine($"Valid: {validation.IsValid}");
        if (!validation.IsValid)
        {
            Console.WriteLine($"Error: {validation.Error}");
        }

        // Convert mnemonic to seed
        var seed = await _crypto.Mnemonic.ToSeedAsync(mnemonic.Phrase, "optional-passphrase");
        Console.WriteLine($"Seed (hex): {BytesToHex(seed, 16)}...");

        // Word suggestions for autocomplete
        var suggestions = await _crypto.Mnemonic.SuggestWordsAsync("aban", 5);
        Console.WriteLine($"Suggestions for 'aban': {string.Join(", ", suggestions)}");
        Console.WriteLine();
    }

    public async Task RunKeypairExample()
    {
        Console.WriteLine("=== Keypair Operations ===");

        // Generate a random keypair
        var keypair = await _crypto.Keypairs.GenerateAsync();
        Console.WriteLine("Generated hybrid keypair:");
        Console.WriteLine($"  Ed25519 public key size: {keypair.PublicKey.Ed25519Bytes.Length} bytes");
        Console.WriteLine($"  Dilithium public key size: {keypair.PublicKey.DilithiumBytes.Length} bytes");
        Console.WriteLine($"  Total public key size: {keypair.PublicKey.Size} bytes");

        // Get addresses for different networks
        Console.WriteLine("\nAddresses:");
        Console.WriteLine($"  Mainnet: {keypair.GetAddress(Network.Mainnet)}");
        Console.WriteLine($"  Testnet: {keypair.GetAddress(Network.Testnet)}");
        Console.WriteLine($"  Devnet: {keypair.GetAddress(Network.Devnet)}");

        // Create keypair from mnemonic (deterministic)
        var mnemonic = await _crypto.Mnemonic.GenerateAsync(24);
        var keypair2 = await _crypto.Keypairs.FromMnemonicAsync(mnemonic.Phrase);
        var addr = keypair2.GetAddress(Network.Mainnet);
        Console.WriteLine($"\nKeypair from mnemonic: {addr[..20]}...");

        // Derive child keypair using BIP-44 path
        var path = DerivationPath.External(0, 0); // m/44'/21337'/0'/0/0
        Console.WriteLine($"Derivation path: {path}");
        Console.WriteLine();
    }

    public async Task RunSigningExample()
    {
        Console.WriteLine("=== Hybrid Signing ===");

        // Generate keypair
        var keypair = await _crypto.Keypairs.GenerateAsync();

        // Sign a message
        var message = Encoding.UTF8.GetBytes("Hello, quantum-resistant world!");
        var signature = await _crypto.Signing.SignAsync(keypair, message);

        Console.WriteLine("Signature created:");
        Console.WriteLine($"  Ed25519 component: {signature.Ed25519Bytes.Length} bytes");
        Console.WriteLine($"  Dilithium component: {signature.DilithiumBytes.Length} bytes");
        Console.WriteLine($"  Total signature size: {signature.Size} bytes");

        // Verify the signature
        var valid = await _crypto.Signing.VerifyAsync(keypair.PublicKey, message, signature);
        Console.WriteLine($"\nVerification result: {valid}");

        // Verify with tampered message fails
        var tamperedMessage = Encoding.UTF8.GetBytes("Hello, tampered message!");
        var invalidResult = await _crypto.Signing.VerifyAsync(keypair.PublicKey, tamperedMessage, signature);
        Console.WriteLine($"Tampered message verification: {invalidResult}");
        Console.WriteLine();
    }

    public async Task RunFalconExample()
    {
        Console.WriteLine("=== Falcon Post-Quantum Signatures ===");

        // Generate Falcon-512 keypair (128-bit security)
        var falcon512 = await _crypto.Falcon.GenerateAsync(FalconVariant.Falcon512);
        Console.WriteLine("Falcon-512 keypair:");
        Console.WriteLine($"  Public key: {falcon512.PublicKey.KeyBytes.Length} bytes");
        Console.WriteLine("  Security level: 128-bit");

        // Generate Falcon-1024 keypair (256-bit security)
        var falcon1024 = await _crypto.Falcon.GenerateAsync(FalconVariant.Falcon1024);
        Console.WriteLine("\nFalcon-1024 keypair:");
        Console.WriteLine($"  Public key: {falcon1024.PublicKey.KeyBytes.Length} bytes");
        Console.WriteLine("  Security level: 256-bit");

        // Sign with Falcon-512
        var message = Encoding.UTF8.GetBytes("Post-quantum secure message");
        var signature = await _crypto.Falcon.SignAsync(falcon512, message);
        Console.WriteLine($"\nFalcon-512 signature: {signature.SignatureBytes.Length} bytes");

        // Verify
        var valid = await _crypto.Falcon.VerifyAsync(falcon512.PublicKey.KeyBytes, message, signature);
        Console.WriteLine($"Verification: {valid}");
        Console.WriteLine();
    }

    public async Task RunSphincsExample()
    {
        Console.WriteLine("=== SPHINCS+ Hash-Based Signatures ===");

        // SPHINCS+ variants with different security levels
        var variants = new (SphincsVariant Variant, int Security, int SigSize, string Name)[]
        {
            (SphincsVariant.Shake128s, 128, 7856, "SHAKE128S"),
            (SphincsVariant.Shake192s, 192, 16224, "SHAKE192S"),
            (SphincsVariant.Shake256s, 256, 29792, "SHAKE256S"),
        };

        var message = Encoding.UTF8.GetBytes("Hash-based quantum security");

        foreach (var (variant, security, sigSize, name) in variants)
        {
            var keypair = await _crypto.Sphincs.GenerateAsync(variant);
            Console.WriteLine($"SPHINCS+ {name}:");
            Console.WriteLine($"  Security level: {security}-bit");
            Console.WriteLine($"  Expected signature size: {sigSize} bytes");

            // Sign a message
            var signature = await _crypto.Sphincs.SignAsync(keypair, message);
            Console.WriteLine($"  Actual signature size: {signature.SignatureBytes.Length} bytes");

            // Verify
            var valid = await _crypto.Sphincs.VerifyAsync(keypair.PublicKey.KeyBytes, message, signature);
            Console.WriteLine($"  Verification: {valid}");
            Console.WriteLine();
        }
    }

    public async Task RunKdfExample()
    {
        Console.WriteLine("=== Key Derivation Functions ===");

        // HKDF (HMAC-based Key Derivation Function)
        var seed = Encoding.UTF8.GetBytes("master-secret-key-material-here");
        var hkdfConfig = new DerivationConfig
        {
            Salt = Encoding.UTF8.GetBytes("application-salt"),
            Info = Encoding.UTF8.GetBytes("encryption-key"),
            OutputLength = 32
        };

        var derivedKey = await _crypto.Kdf.DeriveKeyAsync(seed, hkdfConfig);
        Console.WriteLine($"HKDF derived key: {BytesToHex(derivedKey)}");

        // PBKDF2 (Password-Based Key Derivation Function)
        var password = Encoding.UTF8.GetBytes("user-password");
        var pbkdf2Config = new PasswordDerivationConfig
        {
            Salt = Encoding.UTF8.GetBytes("random-salt-value"),
            Iterations = 100000,
            OutputLength = 32
        };

        var passwordKey = await _crypto.Kdf.DeriveFromPasswordAsync(password, pbkdf2Config);
        Console.WriteLine($"PBKDF2 derived key: {BytesToHex(passwordKey)}");
        Console.WriteLine();
    }

    public async Task RunHashExample()
    {
        Console.WriteLine("=== Hash Functions ===");

        var data = Encoding.UTF8.GetBytes("Data to hash");

        // SHA3-256 (FIPS 202)
        var sha3 = await _crypto.Hash.Sha3_256Async(data);
        Console.WriteLine($"SHA3-256: {sha3.Hex}");

        // BLAKE3 (fast, parallel)
        var blake3 = await _crypto.Hash.Blake3Async(data);
        Console.WriteLine($"BLAKE3:   {blake3.Hex}");

        // Keccak-256 (Ethereum compatible)
        var keccak = await _crypto.Hash.Keccak256Async(data);
        Console.WriteLine($"Keccak:   {keccak.Hex}");
        Console.WriteLine();
    }

    private static string BytesToHex(byte[] data, int? maxLen = null)
    {
        var len = maxLen ?? data.Length;
        var sb = new StringBuilder(len * 2);
        for (var i = 0; i < Math.Min(len, data.Length); i++)
        {
            sb.AppendFormat("{0:x2}", data[i]);
        }
        if (maxLen.HasValue && maxLen.Value < data.Length)
        {
            sb.Append("...");
        }
        return sb.ToString();
    }

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

        var crypto = new SynorCrypto(config);
        var example = new CryptoExample(crypto);

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

            // Run examples
            await example.RunMnemonicExample();
            await example.RunKeypairExample();
            await example.RunSigningExample();
            await example.RunFalconExample();
            await example.RunSphincsExample();
            await example.RunKdfExample();
            await example.RunHashExample();
        }
        catch (Exception ex)
        {
            Console.Error.WriteLine($"Error: {ex.Message}");
            Environment.Exit(1);
        }
    }
}
