use crate::config::ServerConfig;
use crate::models::{ProtocolType, WorkerClass};
use falcorn_core::FalcornServer as CoreServer;
use parking_lot::Mutex;
use pyo3::exceptions::{PyRuntimeError, PyValueError};
use pyo3::prelude::*;
use std::sync::Arc;

// ####
// ##       FALCORN SERVER CLASS FOR PYTHON
// #####

/// Falcorn WSGI application server
#[pyclass]
pub struct FalcornServer {
    config: ServerConfig,
    runtime: Arc<Mutex<Option<tokio::runtime::Runtime>>>,
    server_handle: Arc<Mutex<Option<tokio::task::JoinHandle<()>>>>,
}

#[pymethods]
impl FalcornServer {
    /// Create a new Falcorn server
    #[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>,
    ) -> PyResult<Self> {
        let config = ServerConfig::new(
            app_module,
            app_callable,
            host,
            port,
            backlog,
            workers,
            protocol,
            h2c_enabled,
            strict_http,
            worker_class,
            worker_timeout,
            worker_mode,
            max_requests,
            max_requests_jitter,
            max_connections,
            buffer_size,
            keepalive_timeout,
            sync_handler_threads,
            sync_conn_queue_capacity,
            async_worker_threads,
            async_max_blocking_threads,
            pythonpath,
            asgi_event_loop,
            asgi_event_loop_fallback,
            asgi_submit_timeout_ms,
            asgi_scheduler,
            asgi_max_inflight,
            asgi_send_pool_size,
            log_stdout,
            log_level,
            access_log_format,
            access_log,
            error_log,
            plugin_socket,
            plugin_auth_token,
            plugin_drop_policy,
            plugin_max_lagged_events,
            plugin_write_timeout_ms,
            plugin_bus_capacity,
            plugin_max_clients,
            plugin_subscribe_timeout_ms,
            plugin_auth_fail_window_secs,
            plugin_auth_fail_max_attempts,
            plugin_acl_mode,
            plugin_socket_mode,
            metrics_interval_ms,
            metrics_workers_enabled,
            metrics_os_enabled,
            metrics_percentiles_enabled,
            metrics_top_errors_limit,
            control_socket,
            control_auth_token,
            control_acl_mode,
            control_socket_mode,
            ssl_enabled,
            ssl_certfile,
            ssl_keyfile,
        );

        Ok(Self {
            config,
            runtime: Arc::new(Mutex::new(None)),
            server_handle: Arc::new(Mutex::new(None)),
        })
    }

    /// Create from configuration object
    #[staticmethod]
    pub fn from_config(config: ServerConfig) -> Self {
        Self {
            config,
            runtime: Arc::new(Mutex::new(None)),
            server_handle: Arc::new(Mutex::new(None)),
        }
    }

    /// Run the server (blocking)
    pub fn run(&mut self, py: Python) -> PyResult<()> {
        let config = self.config.to_core_config()?;

        config
            .validate()
            .map_err(|e| PyValueError::new_err(e.to_string()))?;

        let rt =
            tokio::runtime::Runtime::new().map_err(|e| PyRuntimeError::new_err(e.to_string()))?;

        let result = py.detach(|| {
            rt.block_on(async {
                let mut server =
                    CoreServer::new(config).map_err(|e| PyRuntimeError::new_err(e.to_string()))?;

                server
                    .run()
                    .map_err(|e| PyRuntimeError::new_err(e.to_string()))
            })
        });

        *self.runtime.lock() = Some(rt);
        result
    }

    /// Start server in background (non-blocking)
    pub fn start(&mut self) -> PyResult<()> {
        let config = self.config.to_core_config()?;

        config
            .validate()
            .map_err(|e| PyValueError::new_err(e.to_string()))?;

        let mut runtime_guard = self.runtime.lock();
        if runtime_guard.is_none() {
            let rt = tokio::runtime::Runtime::new()
                .map_err(|e| PyRuntimeError::new_err(e.to_string()))?;
            *runtime_guard = Some(rt);
        }

        let rt = runtime_guard.as_ref().unwrap();

        let handle = rt.spawn(async move {
            match CoreServer::new(config) {
                Ok(mut server) => {
                    if let Err(e) = server.run() {
                        eprintln!("Server error: {}", e);
                    }
                }
                Err(e) => eprintln!("Failed to create server: {}", e),
            }
        });

        *self.server_handle.lock() = Some(handle);

        Ok(())
    }

    /// Stop the server
    pub fn stop(&mut self) -> PyResult<()> {
        if let Some(handle) = self.server_handle.lock().take() {
            handle.abort();
        }
        Ok(())
    }

    /// Set worker class
    pub fn set_worker_class(&mut self, class: &str) -> PyResult<()> {
        self.config.worker_class = WorkerClass::new(class)?;
        Ok(())
    }

    /// Set worker timeout
    pub fn set_timeout(&mut self, seconds: u64) -> PyResult<()> {
        if seconds == 0 {
            return Err(PyValueError::new_err("timeout must be greater than 0"));
        }
        self.config.worker_timeout = seconds;
        Ok(())
    }

    /// Set keepalive timeout
    pub fn set_keepalive(&mut self, seconds: u64) -> PyResult<()> {
        self.config.keepalive_timeout = seconds;
        Ok(())
    }

    /// Set log level
    pub fn set_log_level(&mut self, level: String) -> PyResult<()> {
        match level.to_uppercase().as_str() {
            "TRACE" | "DEBUG" | "INFO" | "WARN" | "ERROR" => {
                self.config.log_level = level.to_uppercase();
                Ok(())
            }
            _ => Err(PyValueError::new_err(
                "Invalid log level. Must be TRACE, DEBUG, INFO, WARN, or ERROR",
            )),
        }
    }

    /// Add Python path
    pub fn add_pythonpath(&mut self, path: String) -> PyResult<()> {
        self.config.pythonpath.push(path);
        Ok(())
    }

    /// Get current configuration
    pub fn get_config(&self) -> ServerConfig {
        self.config.clone()
    }

    /// Get server status
    pub fn status(&self) -> String {
        format!(
            "Falcorn Server\n  Address: {}:{}\n  Workers: {} ({})\n  App: {}:{}",
            self.config.host,
            self.config.port,
            self.config.get_worker_count(),
            self.config.worker_class.__str__(),
            self.config.app_module,
            self.config.app_callable
        )
    }

    /// String representation
    fn __repr__(&self) -> String {
        format!(
            "FalcornServer(app='{}:{}', host='{}', port={})",
            self.config.app_module, self.config.app_callable, self.config.host, self.config.port
        )
    }

    /// Enter context manager
    fn __enter__(slf: Py<Self>, _py: Python) -> PyResult<Py<Self>> {
        Ok(slf)
    }

    /// Exit context manager
    fn __exit__(
        &mut self,
        _exc_type: &Bound<'_, PyAny>,
        _exc_value: &Bound<'_, PyAny>,
        _traceback: &Bound<'_, PyAny>,
    ) -> PyResult<bool> {
        self.stop()?;
        Ok(false)
    }
}
