use std::{ops::Deref, sync::atomic::AtomicBool};

use tauri::{
    plugin::{Builder, TauriPlugin},
    Manager, Runtime,
};

pub use models::*;

#[cfg(desktop)]
mod desktop;
#[cfg(mobile)]
mod mobile;

mod commands;
mod error;
mod models;

pub use error::{Error, Result};
// Общий контракт для desktop.rs и mobile.rs — commands.rs вызывает эти методы,
// не зная, какая реализация сейчас подставлена (см. impl Deref ниже).
pub trait VpnInterface<R: Runtime>: Send + Sync + 'static {
    fn start_vpn(
        &self,
        config: TunnelConfig,
        ip: String,
        port: i32,
        sni: String,
    ) -> crate::Result<()>;
    fn stop_vpn(&self) -> crate::Result<()>;
    fn check_actual_vpn_status(&self) -> crate::Result<StatusResponse>;
    fn get_installed_apps(&self) -> crate::Result<Vec<AppInfo>>;
    fn launch_app(&self, package_name: String) -> crate::Result<()>;
}
pub struct Vpn<R: Runtime> {
    inner: Box<dyn VpnInterface<R>>,
    pub is_running: AtomicBool, // Добавляем поле
}

impl<R: Runtime> Vpn<R> {
    pub fn new<I: VpnInterface<R>>(inner: I) -> Self {
        Self {
            inner: Box::new(inner),
            is_running: AtomicBool::new(false),
        }
    }
}

// Deref позволяет звать vpn.start_vpn(...) напрямую на Vpn<R>, как будто это
// сама реализация — без него пришлось бы писать vpn.inner.start_vpn(...) и
// светить приватное поле наружу.
impl<R: Runtime> Deref for Vpn<R> {
    type Target = dyn VpnInterface<R>;

    fn deref(&self) -> &Self::Target {
        &*self.inner
    }
}

pub fn init<R: Runtime>() -> TauriPlugin<R> {
    Builder::new("vpn")
        .invoke_handler(tauri::generate_handler![
            commands::start_vpn,
            commands::stop_vpn,
            commands::check_actual_vpn_status,
            commands::get_installed_apps,
            commands::launch_app, // <--- НОВОЕ
        ])
        .setup(|app, api| {
            #[cfg(mobile)]
            let vpn_impl = mobile::init(app, api)?;
            #[cfg(desktop)]
            let vpn_impl = desktop::init(app, api)?;

            let vpn_instance = Vpn::new(vpn_impl);
            app.manage(vpn_instance);
            Ok(())
        })
        .build()
}
