use std::sync::{Arc, Mutex}; // Добавили Arc

use crate::models::*;
use crate::VpnInterface;
use netrunner_client::Session;
use netrunner_client::SessionManager;
use serde::de::DeserializeOwned;
use tauri::Manager; // Важно для app.manage()
use tauri::{plugin::PluginApi, AppHandle, Emitter, Runtime};

pub fn init<R: Runtime, C: DeserializeOwned>(
    app: &AppHandle<R>,
    _api: PluginApi<R, C>,
) -> crate::Result<Vpn<R>> {
    let vpn = Vpn {
        app: app.clone(),
        // Оборачиваем Mutex в Arc, чтобы структуру Vpn можно было клонировать и шарить
        active_session: Arc::new(Mutex::new(None)),
    };

    // 🛑 САМОЕ ВАЖНОЕ: Регистрируем стейт в Tauri, чтобы app.state() больше не падал!
    app.manage(vpn.clone());

    Ok(vpn)
}

pub struct Vpn<R: Runtime> {
    app: AppHandle<R>,
    active_session: Arc<Mutex<Option<Arc<Session>>>>,
}

impl<R: Runtime> Clone for Vpn<R> {
    fn clone(&self) -> Self {
        Self {
            app: self.app.clone(),
            active_session: self.active_session.clone(),
        }
    }
}

impl<R: Runtime> VpnInterface<R> for Vpn<R> {
    fn start_vpn(&self, config: TunnelConfig, ip: String, port: i32, sni: String) -> crate::Result<()> {
        let _ = self.app.emit(
            "status-change",
            StatusResponse {
                status: "connecting".into(),
            },
        );

        // Передаем новые параметры конфига прямо в UniFFI-метод.
        // sni — decoy-хост для ClientHello, tun_fd на десктопе не нужен (None).
        let session = SessionManager::new().spawn_session(
            format!("{}:{}", ip, port),
            sni,
            None,
            ".".into(),
            config.killswitch_enabled,
            config.excluded_apps.clone(),
            config.excluded_domains.clone(),
            config.auth_token.clone(),
        );

        // Сохраняем сессию
        {
            let mut lock = self.active_session.lock().unwrap();
            *lock = Some(session);
        }

        let _ = self.app.emit(
            "status-change",
            StatusResponse {
                status: "connected".into(),
            },
        );

        // --- ФОНОВЫЙ ЦИКЛ СТАТИСТИКИ (Оптимизированный) ---
        let app_handle = self.app.clone();

        // Клонируем умный указатель (Arc), чтобы отдать его внутрь потока
        let session_ref = self.active_session.clone();

        std::thread::spawn(move || {
            loop {
                std::thread::sleep(std::time::Duration::from_secs(1));

                // Теперь мы НЕ обращаемся к app_handle.state(), а проверяем локальную ссылку!
                // Это полностью исключает дедлоки стейта Tauri.
                if session_ref.lock().unwrap().is_none() {
                    eprintln!("--- [DEBUG] VPN Session ended. Stopping desktop stats loop. ---");
                    break;
                }

                let stats = SessionManager::new().get_traffic_stats();

                let _ = app_handle.emit(
                    "traffic-stats",
                    TrafficStatsResponse {
                        rx_bytes: stats.rx_bytes,
                        tx_bytes: stats.tx_bytes,
                        rx_packets: stats.rx_packets,
                        tx_packets: stats.tx_packets,
                    },
                );
            }
        });
        // -----------------------------------------------------------------

        Ok(())
    }

    fn stop_vpn(&self) -> crate::Result<()> {
        let mut lock = self.active_session.lock().unwrap();
        if let Some(session) = lock.take() {
            session.stop();

            let _ = self.app.emit(
                "status-change",
                StatusResponse {
                    status: "idle".into(),
                },
            );
        }
        Ok(())
    }

    fn check_actual_vpn_status(&self) -> crate::Result<StatusResponse> {
        let lock = self.active_session.lock().unwrap();
        let status = if lock.is_some() { "connected" } else { "idle" };

        Ok(StatusResponse {
            status: status.to_string(),
        })
    }

    fn get_installed_apps(&self) -> crate::Result<Vec<AppInfo>> {
        Ok(vec![]) // На десктопе пока отдаем пустоту
    }

    fn launch_app(&self, _package_name: String) -> crate::Result<()> {
        Ok(()) // На десктопе мы блокируем это через UI, так что просто Ok
    }
}
