//! Crypto SDK types for Rust

use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use thiserror::Error;

// ============================================================================
// Enumerations
// ============================================================================

/// Network type for address generation
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Network {
    Mainnet,
    Testnet,
    Devnet,
}

impl Default for Network {
    fn default() -> Self {
        Network::Mainnet
    }
}

/// Falcon variant selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum FalconVariant {
    Falcon512,
    Falcon1024,
}

impl Default for FalconVariant {
    fn default() -> Self {
        FalconVariant::Falcon512
    }
}

impl FalconVariant {
    /// Returns the signature size for this variant
    pub const fn signature_size(&self) -> usize {
        match self {
            FalconVariant::Falcon512 => 690,
            FalconVariant::Falcon1024 => 1330,
        }
    }

    /// Returns the public key size for this variant
    pub const fn public_key_size(&self) -> usize {
        match self {
            FalconVariant::Falcon512 => 897,
            FalconVariant::Falcon1024 => 1793,
        }
    }

    /// Returns the security level in bits
    pub const fn security_level(&self) -> u16 {
        match self {
            FalconVariant::Falcon512 => 128,
            FalconVariant::Falcon1024 => 256,
        }
    }
}

/// SPHINCS+ variant selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum SphincsVariant {
    Shake128s,
    Shake192s,
    Shake256s,
}

impl Default for SphincsVariant {
    fn default() -> Self {
        SphincsVariant::Shake128s
    }
}

impl SphincsVariant {
    /// Returns the signature size for this variant
    pub const fn signature_size(&self) -> usize {
        match self {
            SphincsVariant::Shake128s => 7856,
            SphincsVariant::Shake192s => 16224,
            SphincsVariant::Shake256s => 29792,
        }
    }

    /// Returns the security level in bits
    pub const fn security_level(&self) -> u16 {
        match self {
            SphincsVariant::Shake128s => 128,
            SphincsVariant::Shake192s => 192,
            SphincsVariant::Shake256s => 256,
        }
    }
}

/// Post-quantum algorithm selection
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum PqAlgorithm {
    Dilithium3,
    Falcon512,
    Falcon1024,
    Sphincs128s,
    Sphincs192s,
    Sphincs256s,
}

/// Algorithm family classification
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AlgorithmFamily {
    Classical,
    Lattice,
    HashBased,
    Hybrid,
}

// ============================================================================
// Configuration Types
// ============================================================================

/// Crypto SDK configuration
#[derive(Debug, Clone)]
pub struct CryptoConfig {
    pub api_key: String,
    pub endpoint: String,
    pub timeout_ms: u64,
    pub retries: u32,
    pub debug: bool,
    pub default_network: Network,
}

impl CryptoConfig {
    /// Creates a new config with the given API key
    pub fn new(api_key: impl Into<String>) -> Self {
        Self {
            api_key: api_key.into(),
            endpoint: "https://crypto.synor.io/v1".to_string(),
            timeout_ms: 30000,
            retries: 3,
            debug: false,
            default_network: Network::Mainnet,
        }
    }

    /// Sets the endpoint
    pub fn with_endpoint(mut self, endpoint: impl Into<String>) -> Self {
        self.endpoint = endpoint.into();
        self
    }

    /// Sets the timeout
    pub fn with_timeout(mut self, timeout_ms: u64) -> Self {
        self.timeout_ms = timeout_ms;
        self
    }
}

/// Key derivation configuration
#[derive(Debug, Clone, Default)]
pub struct DerivationConfig {
    pub salt: Option<Vec<u8>>,
    pub info: Option<Vec<u8>>,
    pub output_length: usize,
}

/// Password derivation configuration
#[derive(Debug, Clone)]
pub struct PasswordDerivationConfig {
    pub salt: Vec<u8>,
    pub iterations: u32,
    pub output_length: usize,
}

/// BIP-44 derivation path
#[derive(Debug, Clone, Default)]
pub struct DerivationPath {
    pub account: u32,
    pub change: u32,
    pub index: u32,
}

impl DerivationPath {
    /// Synor coin type for BIP-44
    pub const COIN_TYPE: u32 = 0x5359;

    /// Creates a new derivation path
    pub fn new(account: u32, change: u32, index: u32) -> Self {
        Self { account, change, index }
    }

    /// Creates a path for external addresses
    pub fn external(account: u32, index: u32) -> Self {
        Self { account, change: 0, index }
    }

    /// Creates a path for internal (change) addresses
    pub fn internal(account: u32, index: u32) -> Self {
        Self { account, change: 1, index }
    }
}

impl std::fmt::Display for DerivationPath {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "m/44'/{}'/{}'/{}/{}",
            Self::COIN_TYPE,
            self.account,
            self.change,
            self.index
        )
    }
}

// ============================================================================
// Key Types
// ============================================================================

/// Hybrid public key (Ed25519 + Dilithium3)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridPublicKey {
    /// Ed25519 component (32 bytes)
    pub ed25519: Vec<u8>,
    /// Dilithium3 component (~1952 bytes)
    pub dilithium: Vec<u8>,
}

impl HybridPublicKey {
    /// Returns the total size in bytes
    pub fn size(&self) -> usize {
        self.ed25519.len() + self.dilithium.len()
    }
}

/// Secret key (master seed)
#[derive(Debug, Clone)]
pub struct SecretKey {
    /// Ed25519 seed (32 bytes)
    pub ed25519_seed: Vec<u8>,
    /// Master seed (64 bytes)
    pub master_seed: Vec<u8>,
}

/// Falcon public key
#[derive(Debug, Clone)]
pub struct FalconPublicKey {
    pub variant: FalconVariant,
    pub bytes: Vec<u8>,
}

/// Falcon secret key
#[derive(Debug, Clone)]
pub struct FalconSecretKey {
    pub variant: FalconVariant,
    pub bytes: Vec<u8>,
}

/// SPHINCS+ public key
#[derive(Debug, Clone)]
pub struct SphincsPublicKey {
    pub variant: SphincsVariant,
    pub bytes: Vec<u8>,
}

/// SPHINCS+ secret key
#[derive(Debug, Clone)]
pub struct SphincsSecretKey {
    pub variant: SphincsVariant,
    pub bytes: Vec<u8>,
}

// ============================================================================
// Signature Types
// ============================================================================

/// Hybrid signature (Ed25519 + Dilithium3)
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HybridSignature {
    /// Ed25519 component (64 bytes)
    pub ed25519: Vec<u8>,
    /// Dilithium3 component (~3293 bytes)
    pub dilithium: Vec<u8>,
}

impl HybridSignature {
    /// Returns the total size in bytes
    pub fn size(&self) -> usize {
        self.ed25519.len() + self.dilithium.len()
    }

    /// Serializes the signature to bytes
    pub fn to_bytes(&self) -> Vec<u8> {
        let mut result = Vec::with_capacity(self.size());
        result.extend_from_slice(&self.ed25519);
        result.extend_from_slice(&self.dilithium);
        result
    }

    /// Deserializes a signature from bytes
    pub fn from_bytes(data: &[u8]) -> Result<Self, CryptoError> {
        if data.len() < 64 {
            return Err(CryptoError::InvalidSignature("Too short".to_string()));
        }
        Ok(Self {
            ed25519: data[..64].to_vec(),
            dilithium: data[64..].to_vec(),
        })
    }
}

/// Falcon signature
#[derive(Debug, Clone)]
pub struct FalconSignature {
    pub variant: FalconVariant,
    pub bytes: Vec<u8>,
}

/// SPHINCS+ signature
#[derive(Debug, Clone)]
pub struct SphincsSignature {
    pub variant: SphincsVariant,
    pub bytes: Vec<u8>,
}

// ============================================================================
// Keypair Types
// ============================================================================

/// Hybrid keypair (Ed25519 + Dilithium3)
#[derive(Debug, Clone)]
pub struct HybridKeypair {
    pub public_key: HybridPublicKey,
    pub secret_key: SecretKey,
    addresses: HashMap<Network, String>,
}

impl HybridKeypair {
    /// Returns the address for a network
    pub fn address(&self, network: Network) -> Option<&str> {
        self.addresses.get(&network).map(|s| s.as_str())
    }

    /// Creates a new keypair with addresses
    pub fn new(
        public_key: HybridPublicKey,
        secret_key: SecretKey,
        addresses: HashMap<Network, String>,
    ) -> Self {
        Self { public_key, secret_key, addresses }
    }
}

/// Falcon keypair
#[derive(Debug, Clone)]
pub struct FalconKeypair {
    pub variant: FalconVariant,
    pub public_key: FalconPublicKey,
    pub secret_key: FalconSecretKey,
}

/// SPHINCS+ keypair
#[derive(Debug, Clone)]
pub struct SphincsKeypair {
    pub variant: SphincsVariant,
    pub public_key: SphincsPublicKey,
    pub secret_key: SphincsSecretKey,
}

// ============================================================================
// Mnemonic Types
// ============================================================================

/// BIP-39 mnemonic phrase
#[derive(Debug, Clone)]
pub struct Mnemonic {
    pub phrase: String,
    pub words: Vec<String>,
    pub word_count: usize,
    pub entropy: Vec<u8>,
}

/// Mnemonic validation result
#[derive(Debug, Clone)]
pub struct MnemonicValidation {
    pub valid: bool,
    pub error: Option<String>,
}

// ============================================================================
// Address Types
// ============================================================================

/// Blockchain address
#[derive(Debug, Clone)]
pub struct Address {
    pub address: String,
    pub network: Network,
    pub pubkey_hash: Vec<u8>,
}

// ============================================================================
// Hash Types
// ============================================================================

/// 256-bit hash
#[derive(Debug, Clone)]
pub struct Hash256 {
    pub bytes: Vec<u8>,
    pub hex: String,
}

impl Hash256 {
    /// Creates a hash from bytes
    pub fn new(bytes: Vec<u8>) -> Self {
        let hex = hex::encode(&bytes);
        Self { bytes, hex }
    }
}

// ============================================================================
// Negotiation Types
// ============================================================================

/// Algorithm capabilities for negotiation
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AlgorithmCapabilities {
    pub pq_algorithms: Vec<PqAlgorithm>,
    pub classical: bool,
    pub hybrid: bool,
    pub preferred: Option<PqAlgorithm>,
}

/// Negotiation policy
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NegotiationPolicy {
    pub min_security_level: u16,
    pub prefer_compact: bool,
    pub allow_classical: bool,
    pub required_families: Vec<AlgorithmFamily>,
}

impl Default for NegotiationPolicy {
    fn default() -> Self {
        Self {
            min_security_level: 128,
            prefer_compact: false,
            allow_classical: false,
            required_families: vec![],
        }
    }
}

/// Negotiation result
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NegotiationResult {
    pub algorithm: PqAlgorithm,
    pub security_level: u16,
    pub family: AlgorithmFamily,
    pub hybrid: bool,
}

/// Session parameters after negotiation
#[derive(Debug, Clone)]
pub struct SessionParams {
    pub algorithm: PqAlgorithm,
    pub session_key: Option<Vec<u8>>,
    pub expires_at: Option<i64>,
}

// ============================================================================
// Error Types
// ============================================================================

/// Crypto operation error
#[derive(Debug, Error)]
pub enum CryptoError {
    #[error("Invalid mnemonic: {0}")]
    InvalidMnemonic(String),

    #[error("Invalid key: {0}")]
    InvalidKey(String),

    #[error("Invalid signature: {0}")]
    InvalidSignature(String),

    #[error("Verification failed")]
    VerificationFailed,

    #[error("Derivation failed: {0}")]
    DerivationFailed(String),

    #[error("Algorithm mismatch")]
    AlgorithmMismatch,

    #[error("Negotiation failed: {0}")]
    NegotiationFailed(String),

    #[error("Network error: {0}")]
    NetworkError(String),

    #[error("API error: {message} (code: {code:?})")]
    ApiError { message: String, code: Option<String> },

    #[error("Client closed")]
    ClientClosed,
}

// ============================================================================
// Constants
// ============================================================================

/// Ed25519 public key size
pub const ED25519_PUBLIC_KEY_SIZE: usize = 32;
/// Ed25519 secret key size
pub const ED25519_SECRET_KEY_SIZE: usize = 32;
/// Ed25519 signature size
pub const ED25519_SIGNATURE_SIZE: usize = 64;
/// Dilithium3 public key size
pub const DILITHIUM3_PUBLIC_KEY_SIZE: usize = 1952;
/// Dilithium3 signature size
pub const DILITHIUM3_SIGNATURE_SIZE: usize = 3293;
/// Hybrid signature size
pub const HYBRID_SIGNATURE_SIZE: usize = ED25519_SIGNATURE_SIZE + DILITHIUM3_SIGNATURE_SIZE;
/// BIP-44 coin type for Synor
pub const COIN_TYPE: u32 = 0x5359;
/// Minimum PBKDF2 iterations
pub const MIN_PBKDF2_ITERATIONS: u32 = 10000;
/// Minimum salt length
pub const MIN_SALT_LENGTH: usize = 8;
/// Default API endpoint
pub const DEFAULT_ENDPOINT: &str = "https://crypto.synor.io/v1";
