use serde::{Deserialize, Serialize};
use std::time::Duration;

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct GeyserConfig {
    pub grpc: GrpcSettings,
    pub benchmark: BenchmarkSettings,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct GrpcSettings {
    #[serde(with = "humantime_serde")]
    pub connection_timeout: Duration,
    #[serde(with = "humantime_serde")]
    pub request_timeout: Duration,
    pub max_msg_size: usize,
    pub tls_enabled: bool,
    pub adaptive_window: bool,
    #[serde(with = "humantime_serde", default)]
    pub keepalive_interval: Option<Duration>,
    pub conn_window_size: Option<u32>,
    pub stream_window_size: Option<u32>,
    pub no_delay: bool,
    #[serde(with = "humantime_serde", default)]
    pub tcp_keepalive: Option<Duration>,
    pub channel_buffer: Option<usize>,
}

#[derive(Debug, Clone, Deserialize, Serialize)]
pub struct BenchmarkSettings {
    pub extra_slots_pct: f32,
    pub ping_samples: usize,
}

impl Default for GeyserConfig {
    fn default() -> Self {
        Self {
            grpc: GrpcSettings {
                connection_timeout: Duration::from_secs(30),
                request_timeout: Duration::from_secs(30),
                max_msg_size: 1024 * 1024,
                tls_enabled: true,
                adaptive_window: false,
                keepalive_interval: Some(Duration::from_secs(30)),
                conn_window_size: Some(65535),
                stream_window_size: Some(65535),
                no_delay: true,
                tcp_keepalive: Some(Duration::from_secs(60)),
                channel_buffer: Some(64),
            },
            benchmark: BenchmarkSettings {
                extra_slots_pct: 0.1,
                ping_samples: 20,
            },
        }
    }
}

impl GeyserConfig {
    pub fn from_file(path: &str) -> anyhow::Result<Self> {
        let content = std::fs::read_to_string(path)?;
        Ok(toml::from_str(&content)?)
    }
}

#[derive(Clone)]
pub struct ConnectionParams {
    pub url: String,
    pub token: Option<String>,
    pub connection_timeout: Duration,
    pub request_timeout: Duration,
    pub max_msg_size: usize,
    pub tls_enabled: bool,
    pub adaptive_window: bool,
    pub keepalive_interval: Option<Duration>,
    pub conn_window_size: Option<u32>,
    pub stream_window_size: Option<u32>,
    pub no_delay: bool,
    pub tcp_keepalive: Option<Duration>,
    pub channel_buffer: Option<usize>,
}

impl ConnectionParams {
    pub fn from_config(url: String, token: Option<String>, cfg: &GeyserConfig) -> Self {
        let g = &cfg.grpc;
        Self {
            url,
            token,
            connection_timeout: g.connection_timeout,
            request_timeout: g.request_timeout,
            max_msg_size: g.max_msg_size,
            tls_enabled: g.tls_enabled,
            adaptive_window: g.adaptive_window,
            keepalive_interval: g.keepalive_interval,
            conn_window_size: g.conn_window_size,
            stream_window_size: g.stream_window_size,
            no_delay: g.no_delay,
            tcp_keepalive: g.tcp_keepalive,
            channel_buffer: g.channel_buffer,
        }
    }
}

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GrpcSettingsSummary {
    pub connection_timeout_ms: u64,
    pub request_timeout_ms: u64,
    pub max_msg_size: usize,
    pub tls_enabled: bool,
    pub adaptive_window: bool,
    pub conn_window_size: Option<u32>,
    pub stream_window_size: Option<u32>,
}

impl From<&GeyserConfig> for GrpcSettingsSummary {
    fn from(cfg: &GeyserConfig) -> Self {
        let g = &cfg.grpc;
        Self {
            connection_timeout_ms: g.connection_timeout.as_millis() as u64,
            request_timeout_ms: g.request_timeout.as_millis() as u64,
            max_msg_size: g.max_msg_size,
            tls_enabled: g.tls_enabled,
            adaptive_window: g.adaptive_window,
            conn_window_size: g.conn_window_size,
            stream_window_size: g.stream_window_size,
        }
    }
}
