//! Federation Error Types

use std::fmt;

/// Federation error type
#[derive(Debug)]
pub enum FederationError {
    /// Store not found
    StoreNotFound(String),
    
    /// Store type mismatch
    TypeMismatch {
        expected: super::StoreType,
        got: super::StoreType,
    },
    
    /// Downcast failed
    DowncastFailed,
    
    /// Store already registered
    StoreAlreadyRegistered(String),
    
    /// Query error
    QueryError(String),
    
    /// Write error
    WriteError(String),
    
    /// Transaction error
    TransactionError(String),
    
    /// Transaction commit failed
    CommitFailed {
        tx_id: String,
        db_alias: String,
        source: Box<dyn std::error::Error + Send + Sync>,
    },
    
    /// Index error
    IndexError(String),
    
    /// Unsupported operation
    UnsupportedOperation(String),
    
    /// IO error
    IoError(std::io::Error),
    
    /// Serialization error
    SerializationError(String),
    
    /// Lock error
    LockError(String),
    
    /// Timeout error
    Timeout(String),
    
    /// Configuration error
    ConfigError(String),
    
    /// Storage/persistence error
    StorageError(String),
    
    /// Permission denied
    PermissionDenied {
        caller: String,
        required: String,
    },
    
    /// Circuit breaker is open for a store
    CircuitBreakerOpen {
        alias: String,
    },
    
    /// Rate limit exceeded
    RateLimitExceeded,
    
    /// Store is temporarily unavailable
    StoreUnavailable(String),
    
    /// Record not found
    RecordNotFound {
        id: String,
    },
    
    /// Record has no ownership metadata
    NoOwnership {
        id: String,
    },
    
    /// Protection level error (Layer 0 denial)
    ProtectionError {
        reason: String,
    },
    
    /// Internal error
    Internal(String),
}

impl fmt::Display for FederationError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match self {
            Self::StoreNotFound(alias) => write!(f, "Store not found: {}", alias),
            Self::TypeMismatch { expected, got } => {
                write!(f, "Store type mismatch: expected {:?}, got {:?}", expected, got)
            }
            Self::DowncastFailed => write!(f, "Failed to downcast store to specific type"),
            Self::StoreAlreadyRegistered(alias) => {
                write!(f, "Store already registered: {}", alias)
            }
            Self::QueryError(msg) => write!(f, "Query error: {}", msg),
            Self::WriteError(msg) => write!(f, "Write error: {}", msg),
            Self::TransactionError(msg) => write!(f, "Transaction error: {}", msg),
            Self::CommitFailed { tx_id, db_alias, source } => {
                write!(f, "Commit failed for tx {} on {}: {}", tx_id, db_alias, source)
            }
            Self::IndexError(msg) => write!(f, "Index error: {}", msg),
            Self::UnsupportedOperation(msg) => write!(f, "Unsupported operation: {}", msg),
            Self::IoError(e) => write!(f, "IO error: {}", e),
            Self::SerializationError(msg) => write!(f, "Serialization error: {}", msg),
            Self::LockError(msg) => write!(f, "Lock error: {}", msg),
            Self::Timeout(msg) => write!(f, "Timeout: {}", msg),
            Self::ConfigError(msg) => write!(f, "Config error: {}", msg),
            Self::StorageError(msg) => write!(f, "Storage error: {}", msg),
            Self::PermissionDenied { caller, required } => {
                write!(f, "Permission denied: {} requires {}", caller, required)
            }
            Self::CircuitBreakerOpen { alias } => {
                write!(f, "Circuit breaker open for store: {}", alias)
            }
            Self::RateLimitExceeded => write!(f, "Rate limit exceeded"),
            Self::StoreUnavailable(alias) => write!(f, "Store unavailable: {}", alias),
            Self::RecordNotFound { id } => write!(f, "Record not found: {}", id),
            Self::NoOwnership { id } => write!(f, "Record has no ownership metadata: {}", id),
            Self::ProtectionError { reason } => write!(f, "Protection error: {}", reason),
            Self::Internal(msg) => write!(f, "Internal error: {}", msg),
        }
    }
}

impl std::error::Error for FederationError {
    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
        match self {
            Self::IoError(e) => Some(e),
            _ => None,
        }
    }
}

impl From<std::io::Error> for FederationError {
    fn from(e: std::io::Error) -> Self {
        Self::IoError(e)
    }
}

/// Result type for federation operations
pub type Result<T> = std::result::Result<T, FederationError>;
