//! Builder helpers for AthenaClient configuration.
use crate::client::backend::{BackendError, BackendType};
use crate::client::config::{ClientConfig, ConnectionConfig, HealthConfig, PoolConfig};
use std::time::Duration;
use thiserror::Error;

/// Possible errors while building an Athena client configuration.
#[derive(Error, Debug)]
pub enum BuilderError {
    #[error("backend type was not specified")]
    MissingBackend,
    #[error("connection URL is required")]
    MissingUrl,
}

/// Fluent builder for Athena clients.
pub struct AthenaClientBuilder {
    backend: Option<BackendType>,
    url: Option<String>,
    key: Option<String>,
    ssl: Option<bool>,
    port: Option<u16>,
    database: Option<String>,
    pool: PoolConfig,
    health: HealthConfig,
}

impl AthenaClientBuilder {
    pub fn new() -> Self {
        Self {
            backend: None,
            url: None,
            key: None,
            ssl: None,
            port: None,
            database: None,
            pool: PoolConfig::default(),
            health: HealthConfig::default(),
        }
    }

    pub fn backend(mut self, backend: BackendType) -> Self {
        self.backend = Some(backend);
        self
    }

    pub fn url(mut self, url: impl Into<String>) -> Self {
        self.url = Some(url.into());
        self
    }

    pub fn key(mut self, key: impl Into<String>) -> Self {
        self.key = Some(key.into());
        self
    }

    pub fn ssl(mut self, enabled: bool) -> Self {
        self.ssl = Some(enabled);
        self
    }

    pub fn port(mut self, port: u16) -> Self {
        self.port = Some(port);
        self
    }

    pub fn database(mut self, database: impl Into<String>) -> Self {
        self.database = Some(database.into());
        self
    }

    pub fn max_connections(mut self, max: u32) -> Self {
        self.pool.max_connections = max;
        self
    }

    pub fn min_connections(mut self, min: u32) -> Self {
        self.pool.min_connections = min;
        self
    }

    pub fn connection_timeout(mut self, timeout: Duration) -> Self {
        self.pool.connection_timeout = timeout;
        self
    }

    pub fn idle_timeout(mut self, timeout: Duration) -> Self {
        self.pool.idle_timeout = timeout;
        self
    }

    pub fn health_tracking(mut self, enabled: bool) -> Self {
        self.health.enabled = enabled;
        self
    }

    pub fn circuit_breaker_threshold(mut self, threshold: u32) -> Self {
        self.health.circuit_breaker_threshold = threshold;
        self
    }

    pub fn circuit_breaker_timeout(mut self, timeout: Duration) -> Self {
        self.health.circuit_breaker_timeout = timeout;
        self
    }

    pub fn health_check_interval(mut self, interval: Duration) -> Self {
        self.health.check_interval = interval;
        self
    }

    /// Finalize builder into shared configuration.
    pub fn build_config(self) -> Result<ClientConfig, BuilderError> {
        let backend_type = self.backend.ok_or(BuilderError::MissingBackend)?;
        let url = self.url.ok_or(BuilderError::MissingUrl)?;
        let mut connection = ConnectionConfig::new(url);

        if let Some(key) = self.key {
            connection.key = Some(key);
        }

        if let Some(ssl) = self.ssl {
            connection.ssl = ssl;
        }

        connection.port = self.port;
        connection.database = self.database;

        Ok(ClientConfig::new(
            backend_type,
            connection,
            self.pool,
            self.health,
        ))
    }
}

impl From<BuilderError> for BackendError {
    fn from(value: BuilderError) -> Self {
        BackendError::Generic(value.to_string())
    }
}
