use std::{
    collections::HashMap,
    sync::{
        Arc, Mutex, OnceLock,
        atomic::{AtomicBool, Ordering},
    },
};

use crate::modules::{
    error::ConvertToPyErr,
    types::{
        diff_tool::DiffTool,
        events::features::{
            callback_token::CallbackToken, events_type::EventsType, polling_eventify::Polling,
            polling_status::PollingStatus,
        },
        listener::Listener,
        toast::Toast,
    },
};

use pyo3::{
    Bound, Py, PyAny, PyErr, PyResult, Python,
    exceptions::{PyRuntimeError, PyTypeError},
    pymethods,
    types::PyAnyMethods,
};

use serde::Serialize;
use serde_json::to_string_pretty;

use tokio::{
    runtime::Runtime,
    time::{Duration, sleep},
};

static RUNTIME: OnceLock<Runtime> = OnceLock::new();

#[derive(Debug, Clone, Serialize)]
struct _DTOForRegistry {
    handler: String,
    events_type: EventsType,
    is_active: bool,
    comment: String,
}

#[pymethods]
impl Polling {
    /// 创建一个新的 Polling 实例.
    ///
    /// Args:
    ///
    ///     listener (Listener): 用于获取通知的监听器实例.
    ///     interval (int): 轮询间隔时间 (毫秒) .
    ///
    /// Returns:
    ///
    ///     Polling: 返回一个新的 Polling 对象.
    #[new]
    pub fn new(listener: Listener, interval: i32) -> PyResult<Self> {
        Ok(Self {
            listener,
            interval,
            registry: Arc::new(Mutex::new(HashMap::new())),
            running: Arc::new(AtomicBool::new(false)),
            interval_shared: Arc::new(Mutex::new(interval)),
        })
    }

    /// 注册一个全局轮询事件回调函数, 该回调会接收所有类型的事件.
    ///
    /// Args:
    ///
    ///     handler (Callable): 一个可调用对象, 接收一个 Diff 参数.
    ///
    /// Returns:
    ///
    ///     CallbackToken: 用于后续取消注册的令牌.
    ///
    /// Raises:
    ///
    ///     TypeError: 如果 handler 不是可调用的函数
    pub fn register_polling_event_callback(
        &self,
        handler: Bound<'_, PyAny>,
    ) -> PyResult<CallbackToken> {
        let token: String = "[WNL PlaceHolder] NO COMMENT".to_string();
        (&*self).register_with_comment(handler, token)
    }

    pub fn register_with_comment(
        &self,
        handler: Bound<'_, PyAny>,
        comment: String,
    ) -> PyResult<CallbackToken> {
        if !handler.is_callable() {
            return Err(PyErr::new::<PyTypeError, _>(
                "[WNL Error] Handler must be callable",
            ));
        }
        let token: CallbackToken = CallbackToken::new();
        let py_handler: Py<PyAny> = handler.unbind();
        let mut reg = (&*self.registry).lock().auto()?;
        (&mut *reg).insert(
            (&token).clone(),
            (py_handler, EventsType::All, true, comment),
        );
        Ok(token)
    }

    /// 注销指定令牌对应的回调函数.
    ///
    /// Args:
    ///
    ///     token (CallbackToken): 要取消注册的回调令牌.
    ///
    /// Returns:
    ///
    ///     PollingStatus: 返回 Success 如果成功移除, 否则返回 Failed.
    pub fn unregister(&self, token: CallbackToken) -> PyResult<PollingStatus> {
        let mut reg = self.registry.lock().auto()?;
        if reg.remove(&token).is_some() {
            Ok(PollingStatus::Success)
        } else {
            Ok(PollingStatus::Failed)
        }
    }

    /// 注册一个仅针对特定事件类型的回调函数.
    ///
    /// Args:
    ///
    ///     handler (Callable): 接收 Diff 参数的可调用对象.
    ///     for_type (EventsType): 指定该回调只响应的通知类型
    ///
    /// Returns:
    ///
    ///     CallbackToken: 用于后续取消注册的令牌.
    ///
    /// Raises:
    ///
    ///     TypeError: 如果 handler 不是可调用的.
    pub fn on_type_callback(
        &self,
        handler: Bound<'_, PyAny>,
        for_type: EventsType,
    ) -> PyResult<CallbackToken> {
        if !handler.is_callable() {
            return Err(PyErr::new::<PyTypeError, _>(
                "[WNL Error] Handler must be callable",
            ));
        }
        let token = CallbackToken::new();
        let py_handler = handler.unbind();
        let mut reg = self.registry.lock().auto()?;
        reg.insert(
            token.clone(),
            (
                py_handler,
                for_type,
                true,
                "[WNL PlaceHolder] NO COMMENT".to_string(),
            ),
        );
        Ok(token)
    }

    /// 启动事件循环, 并将可能的回调函数投入任务中
    ///
    /// 如果轮询已经在运行, 则立即返回 Success.
    ///
    /// Returns:
    ///
    ///     PollingStatus: 返回 Success.
    pub fn start_all(&self) -> PyResult<PollingStatus> {
        if self.running.load(Ordering::SeqCst) {
            return Ok(PollingStatus::Success);
        }
        self.running.store(true, Ordering::SeqCst);

        let listener = self.listener.clone();
        let registry = self.registry.clone();
        let running = self.running.clone();
        let interval_shared = self.interval_shared.clone();

        let rt = RUNTIME.get_or_init(|| Runtime::new().expect("Failed to create tokio runtime"));
        rt.spawn(async move {
            Self::run_polling(listener, registry, running, interval_shared).await;
        });

        Ok(PollingStatus::Success)
    }

    /// 停止所有轮询任务.
    ///
    /// Returns:
    ///
    ///     PollingStatus: 返回 Success.
    pub fn stop_all(&self) -> PyResult<PollingStatus> {
        self.running.store(false, Ordering::SeqCst);
        Ok(PollingStatus::Success)
    }

    /// 激活指定令牌的回调函数, 使其开始处理事件.
    ///
    /// Args:
    ///
    ///     token (CallbackToken): 要激活的回调令牌.
    ///
    /// Returns:
    ///
    ///     PollingStatus: 如果找到该令牌则返回 Success, 否则返回 Failed.
    pub fn polling_for(&self, token: CallbackToken) -> PyResult<PollingStatus> {
        let mut reg = self.registry.lock().auto()?;
        if let Some((_, _, active, _)) = reg.get_mut(&token) {
            *active = true;
            Ok(PollingStatus::Success)
        } else {
            Ok(PollingStatus::Failed)
        }
    }

    /// 停止指定令牌的回调函数, 使其不再处理事件.
    ///
    /// Args:
    ///
    ///     token (CallbackToken): 要暂停的回调令牌.
    ///
    /// Returns:
    ///
    ///     PollingStatus: 如果找到该令牌则返回 Success, 否则返回 Failed.
    pub fn stop_for(&self, token: CallbackToken) -> PyResult<PollingStatus> {
        let mut reg = self.registry.lock().auto()?;
        if let Some((_, _, active, _)) = reg.get_mut(&token) {
            *active = false;
            Ok(PollingStatus::Success)
        } else {
            Ok(PollingStatus::Failed)
        }
    }

    /// 动态修改轮询间隔时间.
    ///
    /// Args:
    ///
    ///     interval (int): 新的轮询间隔时间 (毫秒) .
    pub fn change_interval(&mut self, interval: i32) {
        self.interval = interval;
        *self.interval_shared.lock().unwrap() = interval;
    }

    /// 返回当前注册表的内容字符串
    ///
    /// Returns:
    /// ```json
    /// {
    ///     "CallbackToken(x)": {
    ///         "handler": "Py(0x..abcdefg)",
    ///         "events_type": "All/New/Remove",
    ///         "is_active": bool
    ///     }, ...
    /// }
    /// ```
    pub fn show_registry(&self) -> Result<String, PyErr> {
        let guard = self.registry.lock().map_err(|e| {
            PyRuntimeError::new_err(format!("[WNL Error] Failed to lock registry: {:?}", e))
        })?;

        let serializable_registry: HashMap<String, _DTOForRegistry> = (&*guard)
            .iter()
            .map(|(token, (py_obj, events_type, flag, comment))| {
                let py_debug_str: Option<String> =
                    Python::try_attach(|_| format!("{:?}", (&*py_obj).as_ref()));
                return (
                    // 其实没有改变什么, 只是这里直接加 return 更清晰一些
                    (&*token).__str__(),
                    _DTOForRegistry {
                        handler: py_debug_str.unwrap(),
                        events_type: (&*events_type).clone(),
                        is_active: *flag,
                        comment: (&*comment).clone(),
                    },
                );
            })
            .collect();
        Ok(to_string_pretty(&serializable_registry).unwrap())
    }

    pub fn change_comment(&self, token: CallbackToken, new_comment: String) -> Result<bool, PyErr> {
        let mut registry = (&*self.registry).lock().map_err(|e| {
            PyRuntimeError::new_err(format!("[WNL Error] Failed to lock registry: {:?}", e))
        })?;

        let mut status: bool = false;

        if let Some(entry) = (&mut *registry).get_mut(&token) {
            entry.3 = new_comment;
            status = true;
        }

        Ok(status)
    }
}

impl Polling {
    async fn run_polling(
        listener: Listener,
        registry: Arc<Mutex<HashMap<CallbackToken, (Py<PyAny>, EventsType, bool, String)>>>,
        running: Arc<AtomicBool>,
        interval_shared: Arc<Mutex<i32>>,
    ) {
        let mut previous: Vec<Toast> = vec![];
        while running.load(Ordering::SeqCst) {
            let ms = *interval_shared.lock().unwrap() as u64;
            let current = match listener.get_all_notifications().await {
                Ok(c) => c,
                Err(e) => {
                    eprintln!("[WNL Polling] get_all_notifications error: {:?}", e);
                    sleep(Duration::from_millis(ms)).await;
                    continue;
                }
            };

            let diff = DiffTool::diff_full(previous, current.clone());
            previous = current;

            if diff.new.is_empty() && diff.remove.is_empty() {
                sleep(Duration::from_millis(ms)).await;
                continue;
            }

            let _ = Python::attach(|py| {
                let py_diff = match Py::new(py, diff.clone()) {
                    Ok(p) => p.into_bound(py).into_any(),
                    Err(_) => return,
                };

                let guard = registry.lock().unwrap();

                let handlers_to_call = guard
                    .iter()
                    .filter_map(|(_, (h, e_type, active, _))| {
                        if !*active {
                            return None;
                        }
                        match e_type {
                            EventsType::New if !diff.new.is_empty() => Some(h),
                            EventsType::Remove if !diff.remove.is_empty() => Some(h),
                            EventsType::All => Some(h),
                            _ => None,
                        }
                    })
                    .collect::<Vec<_>>();

                for handler in handlers_to_call {
                    let _ = handler.call1(py, (&py_diff,));
                }
            });

            sleep(Duration::from_millis(ms)).await;
        }
    }
}
