import Foundation
import SynorCrypto

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

@main
struct CryptoExample {
    static func main() async throws {
        // Initialize client
        let config = CryptoConfig(
            apiKey: ProcessInfo.processInfo.environment["SYNOR_API_KEY"] ?? "your-api-key",
            endpoint: "https://crypto.synor.io/v1",
            timeout: 30,
            retries: 3,
            debug: false,
            defaultNetwork: .mainnet
        )

        let crypto = SynorCrypto(config: config)

        do {
            // Check service health
            let healthy = try await crypto.healthCheck()
            print("Service healthy: \(healthy)\n")

            // Run examples
            try await mnemonicExample(crypto: crypto)
            try await keypairExample(crypto: crypto)
            try await signingExample(crypto: crypto)
            try await falconExample(crypto: crypto)
            try await sphincsExample(crypto: crypto)
            try await kdfExample(crypto: crypto)
            try await hashExample(crypto: crypto)
        } catch {
            print("Error: \(error)")
        }

        await crypto.close()
    }

    static func mnemonicExample(crypto: SynorCrypto) async throws {
        print("=== Mnemonic Operations ===")

        // Generate a 24-word mnemonic (256-bit entropy)
        let mnemonic = try await crypto.mnemonic.generate(wordCount: 24)
        print("Generated mnemonic: \(mnemonic.phrase)")
        print("Word count: \(mnemonic.wordCount)")

        // Validate a mnemonic
        let validation = try await crypto.mnemonic.validate(phrase: mnemonic.phrase)
        print("Valid: \(validation.isValid)")
        if !validation.isValid {
            print("Error: \(validation.error ?? "unknown")")
        }

        // Convert mnemonic to seed
        let seed = try await crypto.mnemonic.toSeed(
            phrase: mnemonic.phrase,
            passphrase: "optional-passphrase"
        )
        print("Seed (hex): \(seed.toHex().prefix(32))...")

        // Word suggestions for autocomplete
        let suggestions = try await crypto.mnemonic.suggestWords(prefix: "aban", limit: 5)
        print("Suggestions for 'aban': \(suggestions.joined(separator: ", "))")

        print()
    }

    static func keypairExample(crypto: SynorCrypto) async throws {
        print("=== Keypair Operations ===")

        // Generate a random keypair
        let keypair = try await crypto.keypairs.generate()
        print("Generated hybrid keypair:")
        print("  Ed25519 public key size: \(keypair.publicKey.ed25519Bytes.count) bytes")
        print("  Dilithium public key size: \(keypair.publicKey.dilithiumBytes.count) bytes")
        print("  Total public key size: \(keypair.publicKey.size) bytes")

        // Get addresses for different networks
        print("\nAddresses:")
        print("  Mainnet: \(keypair.getAddress(network: .mainnet))")
        print("  Testnet: \(keypair.getAddress(network: .testnet))")
        print("  Devnet: \(keypair.getAddress(network: .devnet))")

        // Create keypair from mnemonic (deterministic)
        let mnemonic = try await crypto.mnemonic.generate(wordCount: 24)
        let keypair2 = try await crypto.keypairs.fromMnemonic(phrase: mnemonic.phrase, passphrase: "")
        let addr = keypair2.getAddress(network: .mainnet)
        print("\nKeypair from mnemonic: \(addr.prefix(20))...")

        // Derive child keypair using BIP-44 path
        let path = DerivationPath.external(account: 0, index: 0) // m/44'/21337'/0'/0/0
        print("Derivation path: \(path)")

        print()
    }

    static func signingExample(crypto: SynorCrypto) async throws {
        print("=== Hybrid Signing ===")

        // Generate keypair
        let keypair = try await crypto.keypairs.generate()

        // Sign a message
        let message = "Hello, quantum-resistant world!".data(using: .utf8)!
        let signature = try await crypto.signing.sign(keypair: keypair, message: message)

        print("Signature created:")
        print("  Ed25519 component: \(signature.ed25519Bytes.count) bytes")
        print("  Dilithium component: \(signature.dilithiumBytes.count) bytes")
        print("  Total signature size: \(signature.size) bytes")

        // Verify the signature
        let valid = try await crypto.signing.verify(
            publicKey: keypair.publicKey,
            message: message,
            signature: signature
        )
        print("\nVerification result: \(valid)")

        // Verify with tampered message fails
        let tamperedMessage = "Hello, tampered message!".data(using: .utf8)!
        let invalidResult = try await crypto.signing.verify(
            publicKey: keypair.publicKey,
            message: tamperedMessage,
            signature: signature
        )
        print("Tampered message verification: \(invalidResult)")

        print()
    }

    static func falconExample(crypto: SynorCrypto) async throws {
        print("=== Falcon Post-Quantum Signatures ===")

        // Generate Falcon-512 keypair (128-bit security)
        let falcon512 = try await crypto.falcon.generate(variant: .falcon512)
        print("Falcon-512 keypair:")
        print("  Public key: \(falcon512.publicKey.keyBytes.count) bytes")
        print("  Security level: 128-bit")

        // Generate Falcon-1024 keypair (256-bit security)
        let falcon1024 = try await crypto.falcon.generate(variant: .falcon1024)
        print("\nFalcon-1024 keypair:")
        print("  Public key: \(falcon1024.publicKey.keyBytes.count) bytes")
        print("  Security level: 256-bit")

        // Sign with Falcon-512
        let message = "Post-quantum secure message".data(using: .utf8)!
        let signature = try await crypto.falcon.sign(keypair: falcon512, message: message)
        print("\nFalcon-512 signature: \(signature.signatureBytes.count) bytes")

        // Verify
        let valid = try await crypto.falcon.verify(
            publicKey: falcon512.publicKey.keyBytes,
            message: message,
            signature: signature
        )
        print("Verification: \(valid)")

        print()
    }

    static func sphincsExample(crypto: SynorCrypto) async throws {
        print("=== SPHINCS+ Hash-Based Signatures ===")

        // SPHINCS+ variants with different security levels
        let variants: [(SphincsVariant, Int, Int)] = [
            (.shake128s, 128, 7856),
            (.shake192s, 192, 16224),
            (.shake256s, 256, 29792)
        ]

        // Generate and demonstrate each variant
        for (variant, security, sigSize) in variants {
            let keypair = try await crypto.sphincs.generate(variant: variant)
            print("SPHINCS+ \(variant):")
            print("  Security level: \(security)-bit")
            print("  Expected signature size: \(sigSize) bytes")

            // Sign a message
            let message = "Hash-based quantum security".data(using: .utf8)!
            let signature = try await crypto.sphincs.sign(keypair: keypair, message: message)
            print("  Actual signature size: \(signature.signatureBytes.count) bytes")

            // Verify
            let valid = try await crypto.sphincs.verify(
                publicKey: keypair.publicKey.keyBytes,
                message: message,
                signature: signature
            )
            print("  Verification: \(valid)\n")
        }
    }

    static func kdfExample(crypto: SynorCrypto) async throws {
        print("=== Key Derivation Functions ===")

        // HKDF (HMAC-based Key Derivation Function)
        let seed = "master-secret-key-material-here".data(using: .utf8)!
        let hkdfConfig = DerivationConfig(
            salt: "application-salt".data(using: .utf8)!,
            info: "encryption-key".data(using: .utf8)!,
            outputLength: 32
        )

        let derivedKey = try await crypto.kdf.deriveKey(seed: seed, config: hkdfConfig)
        print("HKDF derived key: \(derivedKey.toHex())")

        // PBKDF2 (Password-Based Key Derivation Function)
        let password = "user-password".data(using: .utf8)!
        let pbkdf2Config = PasswordDerivationConfig(
            salt: "random-salt-value".data(using: .utf8)!,
            iterations: 100_000,
            outputLength: 32
        )

        let passwordKey = try await crypto.kdf.deriveFromPassword(
            password: password,
            config: pbkdf2Config
        )
        print("PBKDF2 derived key: \(passwordKey.toHex())")

        print()
    }

    static func hashExample(crypto: SynorCrypto) async throws {
        print("=== Hash Functions ===")

        let data = "Data to hash".data(using: .utf8)!

        // SHA3-256 (FIPS 202)
        let sha3 = try await crypto.hash.sha3_256(data: data)
        print("SHA3-256: \(sha3.hex)")

        // BLAKE3 (fast, parallel)
        let blake3 = try await crypto.hash.blake3(data: data)
        print("BLAKE3:   \(blake3.hex)")

        // Keccak-256 (Ethereum compatible)
        let keccak = try await crypto.hash.keccak256(data: data)
        print("Keccak:   \(keccak.hex)")

        print()
    }
}

// Extension to convert Data to hex string
extension Data {
    func toHex() -> String {
        return map { String(format: "%02x", $0) }.joined()
    }
}
