use std::collections::HashSet;
use std::sync::Arc;
use tokio::sync::Mutex; 
use tauri::{AppHandle, Emitter};
use irc::client::prelude::*;
use futures::stream::StreamExt;
use crate::message_formatter::format_message;

pub struct ConnectionManager {
    pub client: Option<Arc<Mutex<Client>>>,
    pub channels: HashSet<String>,
    pub connected: bool,
}

impl ConnectionManager {
    pub fn new() -> Self {
        Self {
            client: None,
            channels: HashSet::new(),
            connected: false,
        }
    }

    /// Connect to an IRC server
    pub async fn connect(
        &mut self,
        server: String,
        port: u16,
        nickname: String,
        app_handle: AppHandle,
        use_tls: bool,
    ) -> Result<(), String> {
        if self.connected {
            return Err("Already connected".into());
        }

        let config = Config {
            nickname: Some(nickname.clone()),
            server: Some(server.clone()),
            port: Some(port),
            use_tls: Some(use_tls),
            ..Default::default()
        };

        let client = Client::from_config(config)
            .await
            .map_err(|e| e.to_string())?;
        client.identify().map_err(|e| e.to_string())?;

        let arc_client = Arc::new(Mutex::new(client));
        self.client = Some(arc_client.clone());
        self.connected = true;

        // Spawn a listener for messages
        tokio::spawn({
            let arc_client = arc_client.clone();
            let app_handle = app_handle.clone();
            async move {
                let mut stream = arc_client.lock().await.stream().unwrap(); // <-- .await for Tokio Mutex
                while let Some(message) = stream.next().await.transpose().unwrap() {
                    let msg_str = format_message(&message);
                    let _ = app_handle.emit("irc-message", msg_str);
                }
            }
        });

        Ok(())
    }

    /// Disconnect from IRC server
    pub fn disconnect(&mut self) -> Result<(), String> {
        if let Some(client) = &self.client {
            futures::executor::block_on(client.lock()).send_quit("Bye").ok();
        }
        self.client = None;
        self.channels.clear();
        self.connected = false;
        Ok(())
    }

    /// Join a channel
    pub fn join_channel(&mut self, channel: &str) -> Result<(), String> {
        if let Some(client) = &self.client {
            futures::executor::block_on(client.lock()).send_join(channel).map_err(|e| e.to_string())?;
            self.channels.insert(channel.to_string());
            Ok(())
        } else {
            Err("Not connected".into())
        }
    }

    /// Leave a channel
    pub fn part_channel(&mut self, channel: &str) -> Result<(), String> {
        if let Some(client) = &self.client {
            futures::executor::block_on(client.lock()).send_part(channel).map_err(|e| e.to_string())?;
            self.channels.remove(channel);
            Ok(())
        } else {
            Err("Not connected".into())
        }
    }

    /// Send a message to a channel or user
    pub fn send_message(&self, target: &str, message: &str) -> Result<(), String> {
        if let Some(client) = &self.client {
            futures::executor::block_on(client.lock()).send_privmsg(target, message).map_err(|e| e.to_string())
        } else {
            Err("Not connected".into())
        }
    }

    /// Get list of joined channels
    pub fn list_channels(&self) -> Vec<String> {
        self.channels.iter().cloned().collect()
    }

    /// Check connection state
    pub fn is_connected(&self) -> bool {
        self.connected
    }
}
