import Foundation
import CryptoKit

/// Ed25519 signing operations — Identity Key management
enum Ed25519Crypto {

    // MARK: - Key Generation

    /// Generate Ed25519 keypair
    static func generateKeypair() -> (privateKey: Curve25519.Signing.PrivateKey, publicKey: Curve25519.Signing.PublicKey) {
        let privateKey = Curve25519.Signing.PrivateKey()
        return (privateKey, privateKey.publicKey)
    }

    // MARK: - Serialization

    /// Serialize Ed25519 private key. With password: raw 32B → ECP1. Without: raw 32B.
    /// Matches Python: serialize_ed25519_private(key, password=None)
    static func serializePrivate(_ key: Curve25519.Signing.PrivateKey, password: Data? = nil) throws -> Data {
        let raw = key.rawData  // 32 bytes
        if let password = password {
            return try KeyEncryption.encrypt(raw, password: password)
        }
        return raw
    }

    /// Serialize Ed25519 public key to 32 raw bytes.
    /// Matches Python: serialize_ed25519_public(key)
    static func serializePublic(_ key: Curve25519.Signing.PublicKey) -> Data {
        key.rawData  // 32 bytes
    }

    // MARK: - Loading

    /// Load Ed25519 private key. Auto-detects ECP1 / raw 32B.
    /// Matches Python: load_ed25519_private(data, password=None)
    static func loadPrivate(_ data: Data, password: Data? = nil) throws -> Curve25519.Signing.PrivateKey {
        if KeyEncryption.isECP1Format(data) {
            guard let pwd = password else {
                throw CryptoError.invalidKeyData("ECP1 key requires password")
            }
            let raw = try KeyEncryption.decrypt(data, password: pwd)
            return try Curve25519.Signing.PrivateKey(rawRepresentation: raw)
        }
        if data.count == 32 {
            return try Curve25519.Signing.PrivateKey(rawRepresentation: data)
        }
        throw CryptoError.invalidKeyData("Cannot parse Ed25519 private key (\(data.count) bytes)")
    }

    /// Load Ed25519 public key from 32 raw bytes.
    /// Matches Python: load_ed25519_public(data)
    static func loadPublic(_ data: Data) throws -> Curve25519.Signing.PublicKey {
        guard data.count == 32 else {
            throw CryptoError.invalidKeyData("Ed25519 public key must be 32 bytes, got \(data.count)")
        }
        return try Curve25519.Signing.PublicKey(rawRepresentation: data)
    }

    // MARK: - Sign / Verify

    /// Sign data with Ed25519. Returns 64-byte signature.
    /// Matches Python: ed25519_sign(private_key, data)
    static func sign(_ privateKey: Curve25519.Signing.PrivateKey, data: Data) throws -> Data {
        Data(try privateKey.signature(for: data))
    }

    /// Verify Ed25519 signature.
    /// Matches Python: ed25519_verify(public_key, signature, data)
    static func verify(_ publicKey: Curve25519.Signing.PublicKey, signature: Data, data: Data) -> Bool {
        publicKey.isValidSignature(signature, for: data)
    }
}
