use std::path::PathBuf;
use std::sync::{Arc, Mutex};
use anyhow::Result;
use futures_lite::StreamExt;
use once_cell::sync::Lazy;
use tokio::runtime::Runtime;
use tokio::task::JoinHandle;
use tracing::{error, info};

// Import your existing SyncDir logic and iroh types
use crate::sync_dir::SyncDir;
use iroh::client::docs::LiveEvent;

// --- Global State ---
static RUNTIME: Lazy<Runtime> =
    Lazy::new(|| tokio::runtime::Builder::new_multi_thread().enable_all().build().unwrap());

static SYNC_INSTANCE: Lazy<Mutex<Option<Arc<tokio::sync::Mutex<SyncDir>>>>> =
    Lazy::new(|| Mutex::new(None));

static EVENT_LOOP_HANDLE: Lazy<Mutex<Option<JoinHandle<()>>>> = Lazy::new(|| Mutex::new(None));


// --- Real API Functions ---

pub fn start_sync(sync_dir: String, ticket: Option<String>) -> Result<String> {
    let _guard = RUNTIME.enter();

    let sync_dir_instance = futures::executor::block_on(async {
        SyncDir::new(PathBuf::from(sync_dir), ticket).await
    })?;

    let node_id = sync_dir_instance.node_id().to_string();
    let sync_dir_arc = Arc::new(tokio::sync::Mutex::new(sync_dir_instance));
    
    // Spawn the background event loop
    let instance_for_loop = sync_dir_arc.clone();
    let handle = RUNTIME.spawn(async move {
        info!("Starting iroh event loop...");
        // Get the stream outside the loop to avoid re-locking
        let mut stream = match instance_for_loop.lock().await.subscribe().await {
            Ok(s) => s,
            Err(e) => {
                error!("Failed to subscribe to event stream: {}", e);
                return;
            }
        };

        while let Some(event_res) = stream.next().await {
            if let Ok(event) = event_res {
                info!("Received iroh event: {:?}", event);
                // --- THIS IS THE FIX ---
                // Clone the Arc and spawn a separate, short-lived task for each event.
                // This prevents the event handler from blocking the main event loop.
                let instance_clone = instance_for_loop.clone();
                tokio::spawn(async move {
                    // Lock is now acquired and released inside this small task.
                    let instance = instance_clone.lock().await;
                    match event {
                        LiveEvent::NeighborUp(peer_id) => {
                            instance.add_peer(peer_id).await;
                        }
                        LiveEvent::NeighborDown(peer_id) => {
                            instance.remove_peer(peer_id).await;
                        }
                        LiveEvent::InsertRemote { entry, .. } => {
                            if let Err(e) = instance.write_remote_entry(entry).await {
                                error!("Failed to write remote entry: {}", e);
                            }
                        }
                        _ => {}
                    }
                });
            } else if let Err(e) = event_res {
                error!("Event stream error: {}", e);
            }
        }
    });

    *EVENT_LOOP_HANDLE.lock().unwrap() = Some(handle);
    *SYNC_INSTANCE.lock().unwrap() = Some(sync_dir_arc);
    Ok(node_id)
}

pub fn stop_sync() -> Result<()> {
    let _guard = RUNTIME.enter();

    if let Some(handle) = EVENT_LOOP_HANDLE.lock().unwrap().take() {
        info!("Aborting event loop task...");
        handle.abort();
    }

    if let Some(instance_arc) = SYNC_INSTANCE.lock().unwrap().take() {
        futures::executor::block_on(async {
            let instance = instance_arc.lock().await;
            if let Err(e) = instance.shutdown().await {
                eprintln!("Error during shutdown: {}", e);
            }
        });
    }
    Ok(())
}

// The other functions remain the same
pub fn get_status() -> Result<String> {
     let _guard = RUNTIME.enter();
     let instance_lock = SYNC_INSTANCE.lock().unwrap();

     if let Some(instance_arc) = &*instance_lock {
        let status_str = futures::executor::block_on(async {
            let instance = instance_arc.lock().await;
            match instance.get_sync_status().await {
                Ok(status) => format!(
                    "Peers: {}, Files: {}, Dirs: {}",
                    status.connected_peers, status.total_files, status.total_directories
                ),
                Err(e) => format!("Error getting status: {}", e),
            }
        });
        Ok(status_str)
     } else {
        Ok("Not running.".to_string())
     }
}

pub fn generate_ticket() -> Result<String> {
    let _guard = RUNTIME.enter();
    let instance_lock = SYNC_INSTANCE.lock().unwrap();
    if let Some(instance_arc) = &*instance_lock {
        let ticket = futures::executor::block_on(async {
            let instance = instance_arc.lock().await;
            instance.generate_ticket().await
        })?;
        Ok(ticket)
    } else {
        Err(anyhow::anyhow!("Sync not running, cannot generate ticket."))
    }
}
