//! Configuration types for chainfire-core

use std::net::SocketAddr;
use std::path::PathBuf;
use std::sync::Arc;
use std::time::Duration;

use chainfire_types::node::NodeRole;
use chainfire_types::RaftRole;

// Forward declaration - will be implemented in chainfire-storage
// For now, use a placeholder trait
use async_trait::async_trait;

/// Storage backend trait for pluggable storage
#[async_trait]
pub trait StorageBackend: Send + Sync {
    /// Get a value by key
    async fn get(&self, key: &[u8]) -> std::io::Result<Option<Vec<u8>>>;
    /// Put a value
    async fn put(&self, key: &[u8], value: &[u8]) -> std::io::Result<()>;
    /// Delete a key
    async fn delete(&self, key: &[u8]) -> std::io::Result<bool>;
}

/// Configuration for a cluster node
#[derive(Debug, Clone)]
pub struct ClusterConfig {
    /// Unique node ID
    pub node_id: u64,

    /// Human-readable node name
    pub node_name: String,

    /// Node role (ControlPlane or Worker)
    pub node_role: NodeRole,

    /// Raft participation role (Voter, Learner, or None)
    pub raft_role: RaftRole,

    /// API listen address for client connections
    pub api_addr: Option<SocketAddr>,

    /// Raft listen address for peer-to-peer Raft communication
    pub raft_addr: Option<SocketAddr>,

    /// Gossip listen address for membership discovery
    pub gossip_addr: SocketAddr,

    /// Storage backend configuration
    pub storage: StorageBackendConfig,

    /// Initial cluster members for bootstrap
    pub initial_members: Vec<MemberConfig>,

    /// Whether to bootstrap the cluster (first node)
    pub bootstrap: bool,

    /// Cluster ID
    pub cluster_id: u64,

    /// Enable gRPC API server
    pub enable_grpc_api: bool,

    /// Timeouts
    pub timeouts: TimeoutConfig,
}

impl Default for ClusterConfig {
    fn default() -> Self {
        Self {
            node_id: 0,
            node_name: String::new(),
            node_role: NodeRole::ControlPlane,
            raft_role: RaftRole::Voter,
            api_addr: None,
            raft_addr: None,
            gossip_addr: "0.0.0.0:7946".parse().unwrap(),
            storage: StorageBackendConfig::Memory,
            initial_members: Vec::new(),
            bootstrap: false,
            cluster_id: 1,
            enable_grpc_api: false,
            timeouts: TimeoutConfig::default(),
        }
    }
}

/// Storage backend configuration
#[derive(Clone)]
pub enum StorageBackendConfig {
    /// In-memory storage (for testing/simple deployments)
    Memory,

    /// RocksDB storage
    RocksDb {
        /// Data directory path
        path: PathBuf,
    },

    /// Custom storage backend
    Custom(Arc<dyn StorageBackend>),
}

impl std::fmt::Debug for StorageBackendConfig {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            StorageBackendConfig::Memory => write!(f, "Memory"),
            StorageBackendConfig::RocksDb { path } => {
                f.debug_struct("RocksDb").field("path", path).finish()
            }
            StorageBackendConfig::Custom(_) => write!(f, "Custom(...)"),
        }
    }
}

/// Configuration for a cluster member
#[derive(Debug, Clone)]
pub struct MemberConfig {
    /// Node ID
    pub id: u64,

    /// Node name
    pub name: String,

    /// Raft address
    pub raft_addr: String,

    /// Client API address
    pub client_addr: String,
}

/// Timeout configuration
#[derive(Debug, Clone)]
pub struct TimeoutConfig {
    /// Raft heartbeat interval
    pub heartbeat_interval: Duration,

    /// Raft election timeout range (min)
    pub election_timeout_min: Duration,

    /// Raft election timeout range (max)
    pub election_timeout_max: Duration,

    /// Connection timeout
    pub connection_timeout: Duration,

    /// Request timeout
    pub request_timeout: Duration,
}

impl Default for TimeoutConfig {
    fn default() -> Self {
        Self {
            heartbeat_interval: Duration::from_millis(150),
            election_timeout_min: Duration::from_millis(300),
            election_timeout_max: Duration::from_millis(600),
            connection_timeout: Duration::from_secs(5),
            request_timeout: Duration::from_secs(10),
        }
    }
}
