# frozen_string_literal: true

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

require 'synor/crypto'

class CryptoExample
  def initialize(crypto)
    @crypto = crypto
  end

  def run_mnemonic_example
    puts '=== Mnemonic Operations ==='

    # Generate a 24-word mnemonic (256-bit entropy)
    mnemonic = @crypto.mnemonic.generate(24)
    puts "Generated mnemonic: #{mnemonic.phrase}"
    puts "Word count: #{mnemonic.word_count}"

    # Validate a mnemonic
    validation = @crypto.mnemonic.validate(mnemonic.phrase)
    puts "Valid: #{validation.valid?}"
    puts "Error: #{validation.error}" unless validation.valid?

    # Convert mnemonic to seed
    seed = @crypto.mnemonic.to_seed(mnemonic.phrase, 'optional-passphrase')
    puts "Seed (hex): #{bytes_to_hex(seed, 16)}..."

    # Word suggestions for autocomplete
    suggestions = @crypto.mnemonic.suggest_words('aban', 5)
    puts "Suggestions for 'aban': #{suggestions.join(', ')}"
    puts
  end

  def run_keypair_example
    puts '=== Keypair Operations ==='

    # Generate a random keypair
    keypair = @crypto.keypairs.generate
    puts 'Generated hybrid keypair:'
    puts "  Ed25519 public key size: #{keypair.public_key.ed25519_bytes.length} bytes"
    puts "  Dilithium public key size: #{keypair.public_key.dilithium_bytes.length} bytes"
    puts "  Total public key size: #{keypair.public_key.size} bytes"

    # Get addresses for different networks
    puts "\nAddresses:"
    puts "  Mainnet: #{keypair.get_address(:mainnet)}"
    puts "  Testnet: #{keypair.get_address(:testnet)}"
    puts "  Devnet: #{keypair.get_address(:devnet)}"

    # Create keypair from mnemonic (deterministic)
    mnemonic = @crypto.mnemonic.generate(24)
    keypair2 = @crypto.keypairs.from_mnemonic(mnemonic.phrase)
    addr = keypair2.get_address(:mainnet)
    puts "\nKeypair from mnemonic: #{addr[0, 20]}..."

    # Derive child keypair using BIP-44 path
    path = Synor::Crypto::DerivationPath.external(0, 0) # m/44'/21337'/0'/0/0
    puts "Derivation path: #{path}"
    puts
  end

  def run_signing_example
    puts '=== Hybrid Signing ==='

    # Generate keypair
    keypair = @crypto.keypairs.generate

    # Sign a message
    message = 'Hello, quantum-resistant world!'.bytes
    signature = @crypto.signing.sign(keypair, message)

    puts 'Signature created:'
    puts "  Ed25519 component: #{signature.ed25519_bytes.length} bytes"
    puts "  Dilithium component: #{signature.dilithium_bytes.length} bytes"
    puts "  Total signature size: #{signature.size} bytes"

    # Verify the signature
    valid = @crypto.signing.verify(keypair.public_key, message, signature)
    puts "\nVerification result: #{valid}"

    # Verify with tampered message fails
    tampered_message = 'Hello, tampered message!'.bytes
    invalid_result = @crypto.signing.verify(keypair.public_key, tampered_message, signature)
    puts "Tampered message verification: #{invalid_result}"
    puts
  end

  def run_falcon_example
    puts '=== Falcon Post-Quantum Signatures ==='

    # Generate Falcon-512 keypair (128-bit security)
    falcon512 = @crypto.falcon.generate(:falcon512)
    puts 'Falcon-512 keypair:'
    puts "  Public key: #{falcon512.public_key.key_bytes.length} bytes"
    puts '  Security level: 128-bit'

    # Generate Falcon-1024 keypair (256-bit security)
    falcon1024 = @crypto.falcon.generate(:falcon1024)
    puts "\nFalcon-1024 keypair:"
    puts "  Public key: #{falcon1024.public_key.key_bytes.length} bytes"
    puts '  Security level: 256-bit'

    # Sign with Falcon-512
    message = 'Post-quantum secure message'.bytes
    signature = @crypto.falcon.sign(falcon512, message)
    puts "\nFalcon-512 signature: #{signature.signature_bytes.length} bytes"

    # Verify
    valid = @crypto.falcon.verify(falcon512.public_key.key_bytes, message, signature)
    puts "Verification: #{valid}"
    puts
  end

  def run_sphincs_example
    puts '=== SPHINCS+ Hash-Based Signatures ==='

    # SPHINCS+ variants with different security levels
    variants = [
      { variant: :shake128s, security: 128, sig_size: 7856, name: 'SHAKE128S' },
      { variant: :shake192s, security: 192, sig_size: 16_224, name: 'SHAKE192S' },
      { variant: :shake256s, security: 256, sig_size: 29_792, name: 'SHAKE256S' }
    ]

    message = 'Hash-based quantum security'.bytes

    variants.each do |v|
      keypair = @crypto.sphincs.generate(v[:variant])
      puts "SPHINCS+ #{v[:name]}:"
      puts "  Security level: #{v[:security]}-bit"
      puts "  Expected signature size: #{v[:sig_size]} bytes"

      # Sign a message
      signature = @crypto.sphincs.sign(keypair, message)
      puts "  Actual signature size: #{signature.signature_bytes.length} bytes"

      # Verify
      valid = @crypto.sphincs.verify(keypair.public_key.key_bytes, message, signature)
      puts "  Verification: #{valid}"
      puts
    end
  end

  def run_kdf_example
    puts '=== Key Derivation Functions ==='

    # HKDF (HMAC-based Key Derivation Function)
    seed = 'master-secret-key-material-here'.bytes
    hkdf_config = {
      salt: 'application-salt'.bytes,
      info: 'encryption-key'.bytes,
      output_length: 32
    }

    derived_key = @crypto.kdf.derive_key(seed, hkdf_config)
    puts "HKDF derived key: #{bytes_to_hex(derived_key)}"

    # PBKDF2 (Password-Based Key Derivation Function)
    password = 'user-password'.bytes
    pbkdf2_config = {
      salt: 'random-salt-value'.bytes,
      iterations: 100_000,
      output_length: 32
    }

    password_key = @crypto.kdf.derive_from_password(password, pbkdf2_config)
    puts "PBKDF2 derived key: #{bytes_to_hex(password_key)}"
    puts
  end

  def run_hash_example
    puts '=== Hash Functions ==='

    data = 'Data to hash'.bytes

    # SHA3-256 (FIPS 202)
    sha3 = @crypto.hash.sha3_256(data)
    puts "SHA3-256: #{sha3.hex}"

    # BLAKE3 (fast, parallel)
    blake3 = @crypto.hash.blake3(data)
    puts "BLAKE3:   #{blake3.hex}"

    # Keccak-256 (Ethereum compatible)
    keccak = @crypto.hash.keccak256(data)
    puts "Keccak:   #{keccak.hex}"
    puts
  end

  private

  def bytes_to_hex(data, max_len = nil)
    len = max_len || data.length
    hex = data[0, len].map { |b| format('%02x', b) }.join
    hex += '...' if max_len && max_len < data.length
    hex
  end
end

# Main execution
if __FILE__ == $PROGRAM_NAME
  # Initialize client
  api_key = ENV.fetch('SYNOR_API_KEY', 'your-api-key')
  config = Synor::Crypto::Config.new(
    api_key: api_key,
    endpoint: 'https://crypto.synor.io/v1',
    timeout: 30,
    retries: 3,
    debug: false,
    default_network: :mainnet
  )

  crypto = Synor::Crypto::Client.new(config)
  example = CryptoExample.new(crypto)

  begin
    # Check service health
    healthy = crypto.health_check
    puts "Service healthy: #{healthy}\n\n"

    # Run examples
    example.run_mnemonic_example
    example.run_keypair_example
    example.run_signing_example
    example.run_falcon_example
    example.run_sphincs_example
    example.run_kdf_example
    example.run_hash_example
  rescue StandardError => e
    warn "Error: #{e.message}"
    exit 1
  end
end
