//! Crypto SDK client implementation

use super::types::*;
use base64::{engine::general_purpose::STANDARD as BASE64, Engine};
use reqwest::Client;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;

/// Main Synor Crypto client
pub struct SynorCrypto {
    config: CryptoConfig,
    client: Client,
    closed: Arc<AtomicBool>,
}

impl SynorCrypto {
    /// Creates a new client
    pub fn new(config: CryptoConfig) -> Self {
        let client = Client::builder()
            .timeout(std::time::Duration::from_millis(config.timeout_ms))
            .build()
            .expect("Failed to create HTTP client");

        Self {
            config,
            client,
            closed: Arc::new(AtomicBool::new(false)),
        }
    }

    /// Returns the default network
    pub fn default_network(&self) -> Network {
        self.config.default_network
    }

    /// Returns the mnemonic client
    pub fn mnemonic(&self) -> MnemonicClient {
        MnemonicClient { crypto: self }
    }

    /// Returns the keypair client
    pub fn keypairs(&self) -> KeypairClient {
        KeypairClient { crypto: self }
    }

    /// Returns the signing client
    pub fn signing(&self) -> SigningClient {
        SigningClient { crypto: self }
    }

    /// Returns the Falcon client
    pub fn falcon(&self) -> FalconClient {
        FalconClient { crypto: self }
    }

    /// Returns the SPHINCS+ client
    pub fn sphincs(&self) -> SphincsClient {
        SphincsClient { crypto: self }
    }

    /// Returns the KDF client
    pub fn kdf(&self) -> KdfClient {
        KdfClient { crypto: self }
    }

    /// Returns the hash client
    pub fn hash(&self) -> HashClient {
        HashClient { crypto: self }
    }

    /// Checks service health
    pub async fn health_check(&self) -> Result<bool, CryptoError> {
        #[derive(Deserialize)]
        struct HealthResponse {
            status: String,
        }

        match self.get::<HealthResponse>("/health").await {
            Ok(r) => Ok(r.status == "healthy"),
            Err(_) => Ok(false),
        }
    }

    /// Closes the client
    pub fn close(&self) {
        self.closed.store(true, Ordering::SeqCst);
    }

    /// Returns true if closed
    pub fn is_closed(&self) -> bool {
        self.closed.load(Ordering::SeqCst)
    }

    async fn get<T: for<'de> Deserialize<'de>>(&self, path: &str) -> Result<T, CryptoError> {
        self.check_closed()?;

        let resp = self
            .client
            .get(format!("{}{}", self.config.endpoint, path))
            .header("Authorization", format!("Bearer {}", self.config.api_key))
            .header("X-SDK-Version", "rust/0.1.0")
            .send()
            .await
            .map_err(|e| CryptoError::NetworkError(e.to_string()))?;

        self.handle_response(resp).await
    }

    async fn post<T: for<'de> Deserialize<'de>, B: Serialize>(
        &self,
        path: &str,
        body: &B,
    ) -> Result<T, CryptoError> {
        self.check_closed()?;

        let resp = self
            .client
            .post(format!("{}{}", self.config.endpoint, path))
            .header("Authorization", format!("Bearer {}", self.config.api_key))
            .header("Content-Type", "application/json")
            .header("X-SDK-Version", "rust/0.1.0")
            .json(body)
            .send()
            .await
            .map_err(|e| CryptoError::NetworkError(e.to_string()))?;

        self.handle_response(resp).await
    }

    async fn handle_response<T: for<'de> Deserialize<'de>>(
        &self,
        resp: reqwest::Response,
    ) -> Result<T, CryptoError> {
        let status = resp.status();
        let text = resp.text().await.map_err(|e| CryptoError::NetworkError(e.to_string()))?;

        if !status.is_success() {
            #[derive(Deserialize)]
            struct ErrorResponse {
                message: Option<String>,
                code: Option<String>,
            }

            let err: ErrorResponse = serde_json::from_str(&text).unwrap_or(ErrorResponse {
                message: Some(format!("HTTP {}", status)),
                code: None,
            });

            return Err(CryptoError::ApiError {
                message: err.message.unwrap_or_else(|| format!("HTTP {}", status)),
                code: err.code,
            });
        }

        serde_json::from_str(&text).map_err(|e| CryptoError::NetworkError(e.to_string()))
    }

    fn check_closed(&self) -> Result<(), CryptoError> {
        if self.is_closed() {
            return Err(CryptoError::ClientClosed);
        }
        Ok(())
    }
}

// ============================================================================
// Mnemonic Client
// ============================================================================

/// Mnemonic operations
pub struct MnemonicClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> MnemonicClient<'a> {
    /// Generates a new random mnemonic
    pub async fn generate(&self, word_count: usize) -> Result<Mnemonic, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            word_count: usize,
        }

        #[derive(Deserialize)]
        struct Response {
            phrase: String,
            words: Vec<String>,
            word_count: usize,
            entropy: Option<String>,
        }

        let resp: Response = self.crypto.post("/mnemonic/generate", &Request { word_count }).await?;

        Ok(Mnemonic {
            phrase: resp.phrase,
            words: resp.words,
            word_count: resp.word_count,
            entropy: resp.entropy.map(|e| BASE64.decode(e).unwrap_or_default()).unwrap_or_default(),
        })
    }

    /// Creates a mnemonic from a phrase
    pub async fn from_phrase(&self, phrase: &str) -> Result<Mnemonic, CryptoError> {
        #[derive(Serialize)]
        struct Request<'a> {
            phrase: &'a str,
        }

        #[derive(Deserialize)]
        struct Response {
            phrase: String,
            words: Vec<String>,
            word_count: usize,
            entropy: Option<String>,
        }

        let resp: Response = self.crypto.post("/mnemonic/from-phrase", &Request { phrase }).await?;

        Ok(Mnemonic {
            phrase: resp.phrase,
            words: resp.words,
            word_count: resp.word_count,
            entropy: resp.entropy.map(|e| BASE64.decode(e).unwrap_or_default()).unwrap_or_default(),
        })
    }

    /// Validates a mnemonic phrase
    pub async fn validate(&self, phrase: &str) -> Result<MnemonicValidation, CryptoError> {
        #[derive(Serialize)]
        struct Request<'a> {
            phrase: &'a str,
        }

        #[derive(Deserialize)]
        struct Response {
            valid: bool,
            error: Option<String>,
        }

        let resp: Response = self.crypto.post("/mnemonic/validate", &Request { phrase }).await?;

        Ok(MnemonicValidation {
            valid: resp.valid,
            error: resp.error,
        })
    }

    /// Derives a seed from a mnemonic
    pub async fn to_seed(&self, phrase: &str, passphrase: &str) -> Result<Vec<u8>, CryptoError> {
        #[derive(Serialize)]
        struct Request<'a> {
            phrase: &'a str,
            passphrase: &'a str,
        }

        #[derive(Deserialize)]
        struct Response {
            seed: String,
        }

        let resp: Response = self.crypto.post("/mnemonic/to-seed", &Request { phrase, passphrase }).await?;

        BASE64.decode(resp.seed).map_err(|e| CryptoError::DerivationFailed(e.to_string()))
    }
}

// ============================================================================
// Keypair Client
// ============================================================================

/// Keypair operations
pub struct KeypairClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> KeypairClient<'a> {
    /// Generates a new random keypair
    pub async fn generate(&self) -> Result<HybridKeypair, CryptoError> {
        let resp: KeypairResponse = self.crypto.post("/keypair/generate", &()).await?;
        Ok(resp.into_keypair())
    }

    /// Creates a keypair from a mnemonic
    pub async fn from_mnemonic(&self, phrase: &str, passphrase: &str) -> Result<HybridKeypair, CryptoError> {
        #[derive(Serialize)]
        struct Request<'a> {
            phrase: &'a str,
            passphrase: &'a str,
        }

        let resp: KeypairResponse = self.crypto.post("/keypair/from-mnemonic", &Request { phrase, passphrase }).await?;
        Ok(resp.into_keypair())
    }

    /// Creates a keypair from a seed
    pub async fn from_seed(&self, seed: &[u8]) -> Result<HybridKeypair, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            seed: String,
        }

        let resp: KeypairResponse = self.crypto.post("/keypair/from-seed", &Request {
            seed: BASE64.encode(seed),
        }).await?;
        Ok(resp.into_keypair())
    }
}

#[derive(Deserialize)]
struct KeypairResponse {
    public_key: PublicKeyResponse,
    secret_key: SecretKeyResponse,
    addresses: HashMap<String, String>,
}

#[derive(Deserialize)]
struct PublicKeyResponse {
    ed25519: String,
    dilithium: String,
}

#[derive(Deserialize)]
struct SecretKeyResponse {
    ed25519_seed: String,
    master_seed: String,
}

impl KeypairResponse {
    fn into_keypair(self) -> HybridKeypair {
        let ed25519 = BASE64.decode(&self.public_key.ed25519).unwrap_or_default();
        let dilithium = BASE64.decode(&self.public_key.dilithium).unwrap_or_default();
        let ed25519_seed = BASE64.decode(&self.secret_key.ed25519_seed).unwrap_or_default();
        let master_seed = BASE64.decode(&self.secret_key.master_seed).unwrap_or_default();

        let mut addresses = HashMap::new();
        for (k, v) in self.addresses {
            if let Ok(network) = serde_json::from_str::<Network>(&format!("\"{}\"", k)) {
                addresses.insert(network, v);
            }
        }

        HybridKeypair::new(
            HybridPublicKey { ed25519, dilithium },
            SecretKey { ed25519_seed, master_seed },
            addresses,
        )
    }
}

// ============================================================================
// Signing Client
// ============================================================================

/// Signing operations
pub struct SigningClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> SigningClient<'a> {
    /// Signs a message with a hybrid keypair
    pub async fn sign(&self, keypair: &HybridKeypair, message: &[u8]) -> Result<HybridSignature, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            secret_key: SecretKeyRequest,
            message: String,
        }

        #[derive(Serialize)]
        struct SecretKeyRequest {
            ed25519_seed: String,
            master_seed: String,
        }

        #[derive(Deserialize)]
        struct Response {
            ed25519: String,
            dilithium: String,
        }

        let resp: Response = self.crypto.post("/sign/hybrid", &Request {
            secret_key: SecretKeyRequest {
                ed25519_seed: BASE64.encode(&keypair.secret_key.ed25519_seed),
                master_seed: BASE64.encode(&keypair.secret_key.master_seed),
            },
            message: BASE64.encode(message),
        }).await?;

        Ok(HybridSignature {
            ed25519: BASE64.decode(resp.ed25519).unwrap_or_default(),
            dilithium: BASE64.decode(resp.dilithium).unwrap_or_default(),
        })
    }

    /// Verifies a hybrid signature
    pub async fn verify(
        &self,
        public_key: &HybridPublicKey,
        message: &[u8],
        signature: &HybridSignature,
    ) -> Result<bool, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            public_key: PublicKeyRequest,
            message: String,
            signature: SignatureRequest,
        }

        #[derive(Serialize)]
        struct PublicKeyRequest {
            ed25519: String,
            dilithium: String,
        }

        #[derive(Serialize)]
        struct SignatureRequest {
            ed25519: String,
            dilithium: String,
        }

        #[derive(Deserialize)]
        struct Response {
            valid: bool,
        }

        let resp: Response = self.crypto.post("/sign/verify", &Request {
            public_key: PublicKeyRequest {
                ed25519: BASE64.encode(&public_key.ed25519),
                dilithium: BASE64.encode(&public_key.dilithium),
            },
            message: BASE64.encode(message),
            signature: SignatureRequest {
                ed25519: BASE64.encode(&signature.ed25519),
                dilithium: BASE64.encode(&signature.dilithium),
            },
        }).await?;

        Ok(resp.valid)
    }
}

// ============================================================================
// Falcon Client
// ============================================================================

/// Falcon operations
pub struct FalconClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> FalconClient<'a> {
    /// Generates a Falcon keypair
    pub async fn generate(&self, variant: FalconVariant) -> Result<FalconKeypair, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            variant: FalconVariant,
        }

        #[derive(Deserialize)]
        struct Response {
            variant: FalconVariant,
            public_key: KeyBytes,
            secret_key: KeyBytes,
        }

        #[derive(Deserialize)]
        struct KeyBytes {
            bytes: String,
        }

        let resp: Response = self.crypto.post("/falcon/generate", &Request { variant }).await?;

        Ok(FalconKeypair {
            variant: resp.variant,
            public_key: FalconPublicKey {
                variant: resp.variant,
                bytes: BASE64.decode(resp.public_key.bytes).unwrap_or_default(),
            },
            secret_key: FalconSecretKey {
                variant: resp.variant,
                bytes: BASE64.decode(resp.secret_key.bytes).unwrap_or_default(),
            },
        })
    }

    /// Signs with Falcon
    pub async fn sign(&self, keypair: &FalconKeypair, message: &[u8]) -> Result<FalconSignature, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            variant: FalconVariant,
            secret_key: String,
            message: String,
        }

        #[derive(Deserialize)]
        struct Response {
            signature: String,
            variant: FalconVariant,
        }

        let resp: Response = self.crypto.post("/falcon/sign", &Request {
            variant: keypair.variant,
            secret_key: BASE64.encode(&keypair.secret_key.bytes),
            message: BASE64.encode(message),
        }).await?;

        Ok(FalconSignature {
            variant: resp.variant,
            bytes: BASE64.decode(resp.signature).unwrap_or_default(),
        })
    }
}

// ============================================================================
// SPHINCS+ Client
// ============================================================================

/// SPHINCS+ operations
pub struct SphincsClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> SphincsClient<'a> {
    /// Generates a SPHINCS+ keypair
    pub async fn generate(&self, variant: SphincsVariant) -> Result<SphincsKeypair, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            variant: SphincsVariant,
        }

        #[derive(Deserialize)]
        struct Response {
            variant: SphincsVariant,
            public_key: KeyBytes,
            secret_key: KeyBytes,
        }

        #[derive(Deserialize)]
        struct KeyBytes {
            bytes: String,
        }

        let resp: Response = self.crypto.post("/sphincs/generate", &Request { variant }).await?;

        Ok(SphincsKeypair {
            variant: resp.variant,
            public_key: SphincsPublicKey {
                variant: resp.variant,
                bytes: BASE64.decode(resp.public_key.bytes).unwrap_or_default(),
            },
            secret_key: SphincsSecretKey {
                variant: resp.variant,
                bytes: BASE64.decode(resp.secret_key.bytes).unwrap_or_default(),
            },
        })
    }
}

// ============================================================================
// KDF Client
// ============================================================================

/// Key derivation operations
pub struct KdfClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> KdfClient<'a> {
    /// Derives a key using HKDF
    pub async fn derive_key(&self, seed: &[u8], config: &DerivationConfig) -> Result<Vec<u8>, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            seed: String,
            salt: Option<String>,
            info: Option<String>,
            output_length: usize,
        }

        #[derive(Deserialize)]
        struct Response {
            key: String,
        }

        let resp: Response = self.crypto.post("/kdf/hkdf", &Request {
            seed: BASE64.encode(seed),
            salt: config.salt.as_ref().map(|s| BASE64.encode(s)),
            info: config.info.as_ref().map(|i| BASE64.encode(i)),
            output_length: config.output_length,
        }).await?;

        BASE64.decode(resp.key).map_err(|e| CryptoError::DerivationFailed(e.to_string()))
    }

    /// Derives a key from a password
    pub async fn derive_from_password(
        &self,
        password: &[u8],
        config: &PasswordDerivationConfig,
    ) -> Result<Vec<u8>, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            password: String,
            salt: String,
            iterations: u32,
            output_length: usize,
        }

        #[derive(Deserialize)]
        struct Response {
            key: String,
        }

        let resp: Response = self.crypto.post("/kdf/pbkdf2", &Request {
            password: BASE64.encode(password),
            salt: BASE64.encode(&config.salt),
            iterations: config.iterations,
            output_length: config.output_length,
        }).await?;

        BASE64.decode(resp.key).map_err(|e| CryptoError::DerivationFailed(e.to_string()))
    }
}

// ============================================================================
// Hash Client
// ============================================================================

/// Hashing operations
pub struct HashClient<'a> {
    crypto: &'a SynorCrypto,
}

impl<'a> HashClient<'a> {
    /// Computes SHA3-256 hash
    pub async fn sha3_256(&self, data: &[u8]) -> Result<Hash256, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            data: String,
        }

        #[derive(Deserialize)]
        struct Response {
            hash: String,
        }

        let resp: Response = self.crypto.post("/hash/sha3-256", &Request {
            data: BASE64.encode(data),
        }).await?;

        let bytes = hex::decode(&resp.hash).unwrap_or_default();
        Ok(Hash256 { bytes, hex: resp.hash })
    }

    /// Computes BLAKE3 hash
    pub async fn blake3(&self, data: &[u8]) -> Result<Hash256, CryptoError> {
        #[derive(Serialize)]
        struct Request {
            data: String,
        }

        #[derive(Deserialize)]
        struct Response {
            hash: String,
        }

        let resp: Response = self.crypto.post("/hash/blake3", &Request {
            data: BASE64.encode(data),
        }).await?;

        let bytes = hex::decode(&resp.hash).unwrap_or_default();
        Ok(Hash256 { bytes, hex: resp.hash })
    }
}
