use crate::models::{ProtocolType, WorkerClass};
use falcorn_core::{
    ProtocolType as CoreProtocolType, ServerConfig as CoreServerConfig,
    WorkerClass as CoreWorkerClass,
};
use pyo3::exceptions::{PyIOError, PyValueError};
use pyo3::prelude::*;

// ####
// ##       SERVER CONFIG FOR PYTHON
// #####
#[pyclass]
#[derive(Clone)]
pub struct ServerConfig {
    #[pyo3(get, set)]
    pub host: String,
    #[pyo3(get, set)]
    pub port: u16,
    #[pyo3(get, set)]
    pub backlog: u32,
    #[pyo3(get, set)]
    pub workers: Option<usize>,
    #[pyo3(get, set)]
    pub protocol: ProtocolType,
    #[pyo3(get, set)]
    pub h2c_enabled: bool,
    #[pyo3(get, set)]
    pub strict_http: bool,
    #[pyo3(get, set)]
    pub worker_class: WorkerClass,
    #[pyo3(get, set)]
    pub worker_timeout: u64,
    #[pyo3(get, set)]
    pub worker_mode: bool,
    #[pyo3(get, set)]
    pub max_requests: Option<usize>,
    #[pyo3(get, set)]
    pub max_requests_jitter: Option<usize>,
    #[pyo3(get, set)]
    pub buffer_size: usize,
    #[pyo3(get, set)]
    pub keepalive_timeout: u64,
    #[pyo3(get, set)]
    pub max_connections: usize,
    #[pyo3(get, set)]
    pub sync_handler_threads: usize,
    #[pyo3(get, set)]
    pub sync_conn_queue_capacity: usize,
    #[pyo3(get, set)]
    pub async_worker_threads: usize,
    #[pyo3(get, set)]
    pub async_max_blocking_threads: usize,
    #[pyo3(get, set)]
    pub app_module: String,
    #[pyo3(get, set)]
    pub app_callable: String,
    #[pyo3(get, set)]
    pub pythonpath: Vec<String>,
    #[pyo3(get, set)]
    pub log_stdout: bool,
    #[pyo3(get, set)]
    pub log_level: String,
    #[pyo3(get, set)]
    pub access_log_format: String,
    #[pyo3(get, set)]
    pub access_log: Option<String>,
    #[pyo3(get, set)]
    pub error_log: Option<String>,
    #[pyo3(get, set)]
    pub asgi_event_loop: String,
    #[pyo3(get, set)]
    pub asgi_event_loop_fallback: bool,
    #[pyo3(get, set)]
    pub asgi_submit_timeout_ms: u64,
    #[pyo3(get, set)]
    pub asgi_scheduler: String,
    #[pyo3(get, set)]
    pub asgi_max_inflight: usize,
    #[pyo3(get, set)]
    pub asgi_send_pool_size: usize,
    #[pyo3(get, set)]
    pub plugin_socket: Option<String>,
    #[pyo3(get, set)]
    pub plugin_auth_token: Option<String>,
    #[pyo3(get, set)]
    pub plugin_drop_policy: String,
    #[pyo3(get, set)]
    pub plugin_max_lagged_events: usize,
    #[pyo3(get, set)]
    pub plugin_write_timeout_ms: u64,
    #[pyo3(get, set)]
    pub plugin_bus_capacity: usize,
    #[pyo3(get, set)]
    pub plugin_max_clients: usize,
    #[pyo3(get, set)]
    pub plugin_subscribe_timeout_ms: u64,
    #[pyo3(get, set)]
    pub plugin_auth_fail_window_secs: u64,
    #[pyo3(get, set)]
    pub plugin_auth_fail_max_attempts: usize,
    #[pyo3(get, set)]
    pub plugin_acl_mode: String,
    #[pyo3(get, set)]
    pub plugin_socket_mode: u32,
    #[pyo3(get, set)]
    pub metrics_interval_ms: u64,
    #[pyo3(get, set)]
    pub metrics_workers_enabled: bool,
    #[pyo3(get, set)]
    pub metrics_os_enabled: bool,
    #[pyo3(get, set)]
    pub metrics_percentiles_enabled: bool,
    #[pyo3(get, set)]
    pub metrics_top_errors_limit: usize,
    #[pyo3(get, set)]
    pub control_socket: Option<String>,
    #[pyo3(get, set)]
    pub control_auth_token: Option<String>,
    #[pyo3(get, set)]
    pub control_acl_mode: String,
    #[pyo3(get, set)]
    pub control_socket_mode: u32,
    #[pyo3(get, set)]
    pub config_path: Option<String>,
    #[pyo3(get, set)]
    pub ssl_enabled: bool,
    #[pyo3(get, set)]
    pub ssl_certfile: Option<String>,
    #[pyo3(get, set)]
    pub ssl_keyfile: Option<String>,
}

impl ServerConfig {
    /// Create from core ServerConfig
    pub(crate) fn from_core_config(config: CoreServerConfig) -> Self {
        let worker_class = match config.worker_class {
            CoreWorkerClass::Sync => WorkerClass::Sync,
            CoreWorkerClass::Async => WorkerClass::Async,
        };

        let protocol = match config.protocol {
            CoreProtocolType::Wsgi => ProtocolType::Wsgi,
            CoreProtocolType::Asgi => ProtocolType::Asgi,
        };

        Self {
            host: config.host,
            port: config.port,
            backlog: config.backlog,
            workers: config.workers,
            worker_class,
            protocol,
            h2c_enabled: config.h2c_enabled,
            strict_http: config.strict_http,
            worker_timeout: config.worker_timeout,
            worker_mode: config.worker_mode,
            max_requests: config.max_requests,
            max_requests_jitter: config.max_requests_jitter,
            buffer_size: config.buffer_size,
            keepalive_timeout: config.keepalive_timeout,
            max_connections: config.max_connections,
            sync_handler_threads: config.sync_handler_threads,
            sync_conn_queue_capacity: config.sync_conn_queue_capacity,
            async_worker_threads: config.async_worker_threads,
            async_max_blocking_threads: config.async_max_blocking_threads,
            app_module: config.app_module,
            app_callable: config.app_callable,
            pythonpath: config.pythonpath.iter().map(|p| p.to_string()).collect(),
            log_stdout: config.log_stdout,
            log_level: config.log_level,
            access_log_format: config.access_log_format,
            access_log: config.access_log,
            error_log: config.error_log,
            asgi_event_loop: config.asgi_event_loop,
            asgi_event_loop_fallback: config.asgi_event_loop_fallback,
            asgi_submit_timeout_ms: config.asgi_submit_timeout_ms,
            asgi_scheduler: config.asgi_scheduler,
            asgi_max_inflight: config.asgi_max_inflight,
            asgi_send_pool_size: config.asgi_send_pool_size,
            plugin_socket: config.plugin_socket,
            plugin_auth_token: config.plugin_auth_token,
            plugin_drop_policy: config.plugin_drop_policy,
            plugin_max_lagged_events: config.plugin_max_lagged_events,
            plugin_write_timeout_ms: config.plugin_write_timeout_ms,
            plugin_bus_capacity: config.plugin_bus_capacity,
            plugin_max_clients: config.plugin_max_clients,
            plugin_subscribe_timeout_ms: config.plugin_subscribe_timeout_ms,
            plugin_auth_fail_window_secs: config.plugin_auth_fail_window_secs,
            plugin_auth_fail_max_attempts: config.plugin_auth_fail_max_attempts,
            plugin_acl_mode: config.plugin_acl_mode,
            plugin_socket_mode: config.plugin_socket_mode,
            metrics_interval_ms: config.metrics_interval_ms,
            metrics_workers_enabled: config.metrics_workers_enabled,
            metrics_os_enabled: config.metrics_os_enabled,
            metrics_percentiles_enabled: config.metrics_percentiles_enabled,
            metrics_top_errors_limit: config.metrics_top_errors_limit,
            control_socket: config.control_socket,
            control_auth_token: config.control_auth_token,
            control_acl_mode: config.control_acl_mode,
            control_socket_mode: config.control_socket_mode,
            config_path: config.config_path,
            ssl_enabled: config.ssl_enabled,
            ssl_certfile: config.ssl_certfile,
            ssl_keyfile: config.ssl_keyfile,
        }
    }

    /// Convert to core ServerConfig
    pub(crate) fn to_core_config(&self) -> PyResult<CoreServerConfig> {
        Ok(CoreServerConfig {
            host: self.host.clone(),
            port: self.port,
            backlog: self.backlog,
            workers: self.workers,
            protocol: self.protocol.to_core(),
            h2c_enabled: self.h2c_enabled,
            strict_http: self.strict_http,
            worker_class: self.worker_class.to_core(),
            worker_timeout: self.worker_timeout,
            worker_mode: self.worker_mode,
            max_requests: self.max_requests,
            max_requests_jitter: self.max_requests_jitter,
            buffer_size: self.buffer_size,
            keepalive_timeout: self.keepalive_timeout,
            max_connections: self.max_connections,
            sync_handler_threads: self.sync_handler_threads,
            sync_conn_queue_capacity: self.sync_conn_queue_capacity,
            async_worker_threads: self.async_worker_threads,
            async_max_blocking_threads: self.async_max_blocking_threads,
            app_module: self.app_module.clone(),
            app_callable: self.app_callable.clone(),
            pythonpath: self.pythonpath.clone(),
            asgi_event_loop: self.asgi_event_loop.clone(),
            asgi_event_loop_fallback: self.asgi_event_loop_fallback,
            asgi_submit_timeout_ms: self.asgi_submit_timeout_ms,
            asgi_scheduler: self.asgi_scheduler.clone(),
            asgi_max_inflight: self.asgi_max_inflight,
            asgi_send_pool_size: self.asgi_send_pool_size,
            log_stdout: self.log_stdout,
            log_level: self.log_level.clone(),
            access_log_format: self.access_log_format.clone(),
            access_log: self.access_log.clone(),
            error_log: self.error_log.clone(),
            plugin_socket: self.plugin_socket.clone(),
            plugin_auth_token: self.plugin_auth_token.clone(),
            plugin_drop_policy: self.plugin_drop_policy.clone(),
            plugin_max_lagged_events: self.plugin_max_lagged_events,
            plugin_write_timeout_ms: self.plugin_write_timeout_ms,
            plugin_bus_capacity: self.plugin_bus_capacity,
            plugin_max_clients: self.plugin_max_clients,
            plugin_subscribe_timeout_ms: self.plugin_subscribe_timeout_ms,
            plugin_auth_fail_window_secs: self.plugin_auth_fail_window_secs,
            plugin_auth_fail_max_attempts: self.plugin_auth_fail_max_attempts,
            plugin_acl_mode: self.plugin_acl_mode.clone(),
            plugin_socket_mode: self.plugin_socket_mode,
            metrics_interval_ms: self.metrics_interval_ms,
            metrics_workers_enabled: self.metrics_workers_enabled,
            metrics_os_enabled: self.metrics_os_enabled,
            metrics_percentiles_enabled: self.metrics_percentiles_enabled,
            metrics_top_errors_limit: self.metrics_top_errors_limit,
            control_socket: self.control_socket.clone(),
            control_auth_token: self.control_auth_token.clone(),
            control_acl_mode: self.control_acl_mode.clone(),
            control_socket_mode: self.control_socket_mode,
            config_path: self.config_path.clone(),
            ssl_enabled: self.ssl_enabled,
            ssl_certfile: self.ssl_certfile.clone(),
            ssl_keyfile: self.ssl_keyfile.clone(),
        })
    }
}

#[pymethods]
impl ServerConfig {
    /// Create a new server configuration
    #[new]
    #[pyo3(
        signature = (
            app_module,
            app_callable,
            host=None,
            port=None,
            backlog=None,
            workers=None,
            protocol=ProtocolType::Wsgi,
            h2c_enabled=None,
            strict_http=None,
            worker_class=WorkerClass::Sync,
            worker_timeout=None,
            worker_mode=None,
            max_requests=None,
            max_requests_jitter=None,
            max_connections=None,
            buffer_size=None,
            keepalive_timeout=None,
            sync_handler_threads=None,
            sync_conn_queue_capacity=None,
            async_worker_threads=None,
            async_max_blocking_threads=None,
            pythonpath=None,
            asgi_event_loop=None,
            asgi_event_loop_fallback=None,
            asgi_submit_timeout_ms=None,
            asgi_scheduler=None,
            asgi_max_inflight=None,
            asgi_send_pool_size=None,
            log_stdout=None,
            log_level=None,
            access_log_format=None,
            access_log=None,
            error_log=None,
            plugin_socket=None,
            plugin_auth_token=None,
            plugin_drop_policy=None,
            plugin_max_lagged_events=None,
            plugin_write_timeout_ms=None,
            plugin_bus_capacity=None,
            plugin_max_clients=None,
            plugin_subscribe_timeout_ms=None,
            plugin_auth_fail_window_secs=None,
            plugin_auth_fail_max_attempts=None,
            plugin_acl_mode=None,
            plugin_socket_mode=None,
            metrics_interval_ms=None,
            metrics_workers_enabled=None,
            metrics_os_enabled=None,
            metrics_percentiles_enabled=None,
            metrics_top_errors_limit=None,
            control_socket=None,
            control_auth_token=None,
            control_acl_mode=None,
            control_socket_mode=None,
            ssl_enabled=None,
            ssl_certfile=None,
            ssl_keyfile=None,
        )
    )]
    pub fn new(
        app_module: String,
        app_callable: String,
        host: Option<String>,
        port: Option<u16>,
        backlog: Option<u32>,
        workers: Option<usize>,
        protocol: ProtocolType,
        h2c_enabled: Option<bool>,
        strict_http: Option<bool>,
        worker_class: WorkerClass,
        worker_timeout: Option<u64>,
        worker_mode: Option<bool>,
        max_requests: Option<u32>,
        max_requests_jitter: Option<u32>,
        max_connections: Option<u32>,
        buffer_size: Option<u32>,
        keepalive_timeout: Option<u32>,
        sync_handler_threads: Option<u32>,
        sync_conn_queue_capacity: Option<u32>,
        async_worker_threads: Option<u32>,
        async_max_blocking_threads: Option<u32>,
        pythonpath: Option<Vec<String>>,
        asgi_event_loop: Option<String>,
        asgi_event_loop_fallback: Option<bool>,
        asgi_submit_timeout_ms: Option<u64>,
        asgi_scheduler: Option<String>,
        asgi_max_inflight: Option<u32>,
        asgi_send_pool_size: Option<u32>,
        log_stdout: Option<bool>,
        log_level: Option<String>,
        access_log_format: Option<String>,
        access_log: Option<String>,
        error_log: Option<String>,
        plugin_socket: Option<String>,
        plugin_auth_token: Option<String>,
        plugin_drop_policy: Option<String>,
        plugin_max_lagged_events: Option<u32>,
        plugin_write_timeout_ms: Option<u64>,
        plugin_bus_capacity: Option<u32>,
        plugin_max_clients: Option<u32>,
        plugin_subscribe_timeout_ms: Option<u64>,
        plugin_auth_fail_window_secs: Option<u64>,
        plugin_auth_fail_max_attempts: Option<u32>,
        plugin_acl_mode: Option<String>,
        plugin_socket_mode: Option<u32>,
        metrics_interval_ms: Option<u64>,
        metrics_workers_enabled: Option<bool>,
        metrics_os_enabled: Option<bool>,
        metrics_percentiles_enabled: Option<bool>,
        metrics_top_errors_limit: Option<u32>,
        control_socket: Option<String>,
        control_auth_token: Option<String>,
        control_acl_mode: Option<String>,
        control_socket_mode: Option<u32>,
        ssl_enabled: Option<bool>,
        ssl_certfile: Option<String>,
        ssl_keyfile: Option<String>,
    ) -> Self {
        Self {
            host: host.unwrap_or_else(|| "127.0.0.1".to_string()),
            port: port.unwrap_or(8000),
            backlog: backlog.unwrap_or(2048),
            workers,
            worker_class,
            protocol,
            h2c_enabled: h2c_enabled.unwrap_or(false),
            strict_http: strict_http.unwrap_or(false),
            worker_timeout: worker_timeout.unwrap_or(30),
            worker_mode: worker_mode.unwrap_or(false),
            max_requests: max_requests.map(|v| v as usize),
            max_requests_jitter: max_requests_jitter.map(|v| v as usize),
            buffer_size: buffer_size.unwrap_or(4096) as usize,
            keepalive_timeout: keepalive_timeout.unwrap_or(5) as u64,
            max_connections: max_connections.unwrap_or(2048) as usize,
            sync_handler_threads: sync_handler_threads.unwrap_or(4) as usize,
            sync_conn_queue_capacity: sync_conn_queue_capacity.unwrap_or(4096) as usize,
            async_worker_threads: async_worker_threads.unwrap_or(4) as usize,
            async_max_blocking_threads: async_max_blocking_threads.unwrap_or(100) as usize,
            app_module,
            app_callable,
            pythonpath: pythonpath.unwrap_or_default(),
            log_stdout: log_stdout.unwrap_or(false),
            log_level: log_level.unwrap_or_else(|| "INFO".to_string()),
            access_log_format: access_log_format
                .unwrap_or_else(|| r#"%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s"#.to_string()),
            access_log,
            error_log,
            asgi_event_loop: asgi_event_loop.unwrap_or_else(|| "asyncio".to_string()),
            asgi_event_loop_fallback: asgi_event_loop_fallback.unwrap_or(true),
            asgi_submit_timeout_ms: asgi_submit_timeout_ms.unwrap_or(30_000),
            asgi_scheduler: asgi_scheduler.unwrap_or_else(|| "task".to_string()),
            asgi_max_inflight: asgi_max_inflight.unwrap_or(2048) as usize,
            asgi_send_pool_size: asgi_send_pool_size.unwrap_or(4096) as usize,
            plugin_socket,
            plugin_auth_token,
            plugin_drop_policy: plugin_drop_policy.unwrap_or_else(|| "drop_oldest".to_string()),
            plugin_max_lagged_events: plugin_max_lagged_events.unwrap_or(2048) as usize,
            plugin_write_timeout_ms: plugin_write_timeout_ms.unwrap_or(500),
            plugin_bus_capacity: plugin_bus_capacity.unwrap_or(8192) as usize,
            plugin_max_clients: plugin_max_clients.unwrap_or(1024) as usize,
            plugin_subscribe_timeout_ms: plugin_subscribe_timeout_ms.unwrap_or(5000),
            plugin_auth_fail_window_secs: plugin_auth_fail_window_secs.unwrap_or(60),
            plugin_auth_fail_max_attempts: plugin_auth_fail_max_attempts.unwrap_or(10) as usize,
            plugin_acl_mode: plugin_acl_mode.unwrap_or_else(|| "same_user".to_string()),
            plugin_socket_mode: plugin_socket_mode.unwrap_or(0o660),
            metrics_interval_ms: metrics_interval_ms.unwrap_or(5000),
            metrics_workers_enabled: metrics_workers_enabled.unwrap_or(true),
            metrics_os_enabled: metrics_os_enabled.unwrap_or(false),
            metrics_percentiles_enabled: metrics_percentiles_enabled.unwrap_or(false),
            metrics_top_errors_limit: metrics_top_errors_limit.unwrap_or(5) as usize,
            control_socket: control_socket
                .or_else(|| Some(falcorn_core::control::ipc::DEFAULT_CONTROL_SOCKET.to_string())),
            control_auth_token,
            control_acl_mode: control_acl_mode.unwrap_or_else(|| "same_user".to_string()),
            control_socket_mode: control_socket_mode.unwrap_or(0o660),
            config_path: None,
            ssl_enabled: ssl_enabled.unwrap_or(false),
            ssl_certfile,
            ssl_keyfile,
        }
    }

    /// Load configuration from TOML file
    #[staticmethod]
    pub fn from_toml(path: String) -> PyResult<Self> {
        let config =
            CoreServerConfig::from_toml(&path).map_err(|e| PyIOError::new_err(e.to_string()))?;

        Ok(Self::from_core_config(config))
    }

    /// Save configuration to TOML file
    pub fn to_toml(&self, path: String) -> PyResult<()> {
        let config = self.to_core_config()?;
        config
            .to_toml(&path)
            .map_err(|e| PyIOError::new_err(e.to_string()))
    }

    /// Validate configuration
    pub fn validate(&self) -> PyResult<()> {
        let config = self.to_core_config()?;
        config
            .validate()
            .map_err(|e| PyValueError::new_err(e.to_string()))
    }

    /// Get worker count (with CPU detection)
    pub fn get_worker_count(&self) -> usize {
        self.workers.unwrap_or_else(num_cpus::get)
    }

    /// String representation
    fn __repr__(&self) -> String {
        format!(
            "ServerConfig(host='{}', port={}, workers={}, worker_class={})",
            self.host,
            self.port,
            self.get_worker_count(),
            self.worker_class.__str__()
        )
    }
}
