// use futures::lock::Mutex;
use tokio::sync::mpsc::UnboundedReceiver;
use tokio::sync::RwLock;
use twitch_irc::login::StaticLoginCredentials;
use twitch_irc::ClientConfig;
use twitch_irc::SecureTCPTransport;
use twitch_irc::TwitchIRCClient;
use twitch_irc::message::PrivmsgMessage;
use twitch_irc::message::ServerMessage;
use twitch_irc::transport::tcp::TCPTransport;
use twitch_irc::transport::tcp::TLS;
// use std::borrow::Borrow;
use std::borrow::BorrowMut;
use std::boxed;
use std::cell::Ref;
use std::env;
use dotenv::dotenv;

use std::collections::HashMap;

use rand::Rng;

// Important to use tokios Mutex here since std Mutex doesn't work with async functions
use tokio::sync::Mutex;



use crate::core::botmodules::BotAction;
use crate::core::botmodules::BotAction;
use crate::core::ratelimiter::RateLimiter;
use crate::core::ratelimiter;

use crate::core::botmodules;
use crate::core::botmodules::{ModulesManager,BotAction};
use crate::core::identity::{IdentityManager,Permissible};

use std::rc::Rc;
use std::cell::RefCell;
use std::sync::Arc;
// use futures::lock::Mutex;

use std::pin::Pin;

//use std::borrow::Borrow;
use core::borrow::Borrow;

// pub type BotAR = Arc<RwLock<BotInstance>>;
use super::botmodules::bot_actions::actions_util::BotAR;


#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum ChType {
    Channel(String),
}


pub use ChType::Channel;



// pub enum ModType {
//     BotModule(String),
// }

// pub use ModType::BotModule;


#[derive(Clone)]
pub struct Chat {
    // pub ratelimiters : HashMap<ChType,RateLimiter>, // used to limit messages sent per channel 
    pub ratelimiters : Arc<Mutex<HashMap<ChType,RateLimiter>>>, // used to limit messages sent per channel 
    pub client : TwitchIRCClient<TCPTransport<TLS>,StaticLoginCredentials>, 
}

impl Chat {


    pub fn init(ratelimiters:HashMap<ChType, RateLimiter>,
        client:TwitchIRCClient<TCPTransport<TLS>, StaticLoginCredentials>) -> Chat {
            Chat{
                ratelimiters : Arc::new(Mutex::new(ratelimiters)),
                client : client,
            } 
    }

    // pub fn init_channel(&mut self, chnl:ChType) -> () {
    pub async fn init_channel(&mut self, chnl:ChType) -> () {
        let n = RateLimiter::new();
        self.ratelimiters.lock().await.insert(chnl,n);
    } 



	// pub async fn say_in_reply_to(&mut self, msg:& PrivmsgMessage , mut outmsg:String) -> () {
    pub async fn say_in_reply_to(&self, msg:& PrivmsgMessage , mut outmsg:String) -> () {
        /*
        formats message before sending to TwitchIRC 

        - [x] Custom String Formatting (e.g., adding random black spaces)
        - [x] Ratelimiter Handling
        - [ ] Checkf if BotActions is Enabled & Caller is Allowed to Run

         */
		
		// self.client.say_in_reply_to(msg,outmsg).await.unwrap();

        // // let contextratelimiter = ratelimiters.get_mut(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
        let a = Arc::clone(&self.ratelimiters);
        let mut a = a.lock().await;

        // let contextratelimiter = self.ratelimiters
        let contextratelimiter = a
            // .get_mut()
            .get_mut(&Channel(String::from(&msg.channel_login)))
            .expect("ERROR: Issue with Rate limiters");
        // let contextratelimiter = self.ratelimiters.get(&msg.channel_login).expect("ERROR: Issue with Rate limiters");
    
        match contextratelimiter.check_limiter() {
            ratelimiter::LimiterResp::Allow => {
                let maxblanks = rand::thread_rng().gen_range(1..=20);
                //let mut outmsg = "GotTrolled ".to_owned();
                // let mut outmsg = "annytfLurk ".to_owned();
    
                for _i in 1..maxblanks {
                    let blankspace: &str = "󠀀";
                    outmsg.push_str(blankspace);
                }
    
                // client.say_in_reply_to(&msg,outmsg).await.unwrap();
                self.client.say_in_reply_to(msg,outmsg).await.unwrap();
                println!("(#{}) > {}", msg.channel_login, "rate limit counter increase");
                contextratelimiter.increment_counter();
                println!("{:?}",self.ratelimiters);
            },
            ratelimiter::LimiterResp::Skip => {
                (); // do nothing otherwise
            }
	
	    }
    }
	
	async fn say(&self, _:String, _:String) -> () {
		// more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
		
		
		// self.client.say(msg,outmsg).await.unwrap();
		
		
	}
	
	
	async fn me(&self, _:String, _:String) -> () {
		// more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
		
		
		// self.client.me(msg,outmsg).await.unwrap();
		
		
	}
	
	async fn me_in_reply_to(&self, _:String, _:String) -> () {
		// more info https://docs.rs/twitch-irc/latest/twitch_irc/client/struct.TwitchIRCClient.html#method.say
		
		
		// self.client.me(msg,outmsg).await.unwrap();
		
		
	}


}


#[derive(Clone)]
pub struct BotManagers {
    // pub botmodules : ModulesManager,
    pub identity : Arc<RwLock<IdentityManager>>,
    pub chat : Chat,
}

impl BotManagers {

    pub fn init(ratelimiters:HashMap<ChType, RateLimiter>,
        client:TwitchIRCClient<TCPTransport<TLS>, StaticLoginCredentials>) 
        -> BotManagers {
        // let a = Arc::new(Mutex::new(BotManagers {
        //     // botmodules : ModulesManager::init(),
        //     identity : Arc::new(Mutex::new(IdentityManager::init())),
        //     chat : Chat::init(ratelimiters,client),
        // }));
        // a
        BotManagers {
            // botmodules : ModulesManager::init(),
            identity : Arc::new(RwLock::new(IdentityManager::init())),
            chat : Chat::init(ratelimiters,client),
        }
    }

    pub fn rIdentity(self) -> Arc<RwLock<IdentityManager>> {
        self.identity
    }

    // pub fn rChat(&self) -> Arc<Mutex<Chat>> {
    //     Arc::new(Mutex::new(self.chat))
    // }
}


pub struct ArcBox<T: Clone>(pub Arc<Mutex<T>>);

impl<T: Clone> ArcBox<T>{
    pub fn inst(&self) -> &Mutex<T> {
        &self.0
    }

}

//#[derive(Clone)]
// #[derive(Copy)] // <-- Cannot be derived
pub struct BotInstance
{
	pub prefix : char,
	pub bot_channel : ChType,
    // pub incoming_messages : UnboundedReceiver<ServerMessage>,
    pub incoming_messages : Arc<RwLock<UnboundedReceiver<ServerMessage>>>,
    // pub incoming_messages : RefCell<UnboundedReceiver<ServerMessage>>,
    // pub chat : Chat,
    pub botmodules : Arc<ModulesManager>,
	pub twitch_oauth : String,
	pub bot_channels : Vec<ChType>,
    // pub identity : IdentityManager,
    // pub botmgrs : Arc<Mutex<BotManagers>>,
    pub botmgrs : BotManagers,
}



impl BotInstance 
{


    // pub fn init() -> BotInstance
    // pub fn init() -> Arc<BotInstance>
    pub async fn init() -> BotInstance
    {
        dotenv().ok();

        let login_name = env::var("login_name").unwrap().to_owned();
        let oauth_token = env::var("access_token").unwrap().to_owned();
        let prefix = env::var("prefix").unwrap().to_owned().chars().next().expect("ERROR : when defining prefix");

        /*
        Vector of channels to join
        */

        let mut botchannels = Vec::new();

        for chnl in env::var("bot_channels").unwrap().split(',') {
            // println!("(Env Var # {})",chnl);
            botchannels.push(Channel(String::from(chnl)));
        }

        let config = ClientConfig::new_simple(
            StaticLoginCredentials::new(login_name.to_owned(), Some(oauth_token.to_owned()))
        );

        let (incoming_messages, client) =
        TwitchIRCClient::<SecureTCPTransport, StaticLoginCredentials>::new(config);

        // hashmap for channels and their associated ratelimiters
        let mut ratelimiters = HashMap::new();

        for Channel(chnl) in &botchannels {
            // For each channel in botchannels

            client.join(chnl.to_owned()).unwrap();

            // ratelimiters are a hashmap of channel and a corresponding rate limiter 
            let n = RateLimiter::new();
            ratelimiters.insert(Channel(String::from(chnl)),n);
            //self.chat.ratelimiters.insert(Channel(String::from(chnl)),n);
        }



        // let bm = &mut ModulesManager::init();

        

        let b = BotInstance {
            prefix : prefix,
            bot_channel : Channel(login_name) ,
            incoming_messages : Arc::new(RwLock::new(incoming_messages)),
            //client : client,
            // chat : Chat {
            //         ratelimiters : ratelimiters,
            //         client : client,
            //     } ,
            botmodules : ModulesManager::init().await,
            twitch_oauth : oauth_token,
            bot_channels : botchannels,    
            // identity : IdentityManager::init(),
            botmgrs : BotManagers::init(ratelimiters,client),
        };


        //println!("{:?}",b.botmgrs.chat.ratelimiters);


        // Arc::new(b)
        //Arc::new(RwLock::new(b))
        b
    }

    // async fn rcv_helper(self) -> Option<ServerMessage> {
    //     // self.incoming_messages.get_mut().recv().await
    //     let mut a = self.incoming_messages;
    //     a.get_mut().recv().await
    // }

    // pub async fn runner(mut self) -> () {
    // pub async fn runner(&'static mut self) -> () {
    pub async fn runner(self) -> () {

        // let bot_am = Arc::new(Mutex::new(self));

        // let mut boxed_bot = Arc::new(RefCell::new(self)); // <-- [ERROR] Future cannot be handled safely 

        let bot = Arc::new(RwLock::new(self));
        

        let join_handle = tokio::spawn(async move {

            // let boxed_bot = Arc::new(Mutex::new(self));
            // let mut boxed_bot = Arc::new(self);
            // let bot = Rc::new(RefCell::new(self));
            // let mut bot = Rc::new(RefCell::new(&self));
            //let bot = Arc::new(Mutex::new(&self));
            // let mut boxed_bot = Arc::new(RefCell::new(self));
            // let mut boxed_bot = Arc::new(Mutex::new(self));

            // while let Some(message) = bot.borrow_mut().incoming_messages.recv().await {

            // let bot = Arc::clone(&botinit);

            // while let Some(message) = bot.lock().unwrap().incoming_messages.recv().await {
            //let b = Arc::clone(&bot);

            // let mut bot = RefCell::new(&self);

            // let mut bota = bot.clone().borrow();

            // let boxed_bot = Rc::new(RefCell::new(self));
            // let  boxed_bot = Rc::new(self);
            // let boxed_bot = Pin::new(Rc::new(self));
            //let mut boxed_bot = Rc::new(RefCell::new(self));
            // let mut a = (*boxed_bot).clone().into_inner();
            // let mut a = Rc::clone(&boxed_bot).borrow_mut();
            //let mut a =  Rc::<Rc<RefCell<BotInstance>>>::Borrow(Rc::clone(&boxed_bot));


            // while let Some(message) = Rc::clone(&boxed_bot).into_inner().incoming_messages.recv().await {
            // while let Some(message) = Rc::<BotInstance>::borrow(Rc::<BotInstance>::as_ref(boxed_bot)) {

            // let a = boxed_bot.borrow();

            // let boxed_bota = boxed_bot.borrow_mut();

            // let a = Rc::try_unwrap(boxed_bot).ok().unwrap().into_inner();

            // let boxed_bot = RefCell::new(Rc::new(self));
            //let boxed_bot = Rc::new(RefCell::new(self));
            // Rc::try_unwrap(boxed_bot).ok().unwrap().into_inner().incoming_messages.recv().await;

            // let a:Borrowed = boxed_bot.borrow();
            // while let Some(message) = Rc::try_unwrap(boxed_bot).ok().unwrap().into_inner().incoming_messages.recv().await {
            //  while let Some(message) = RefCell::new(self).borrow_mut().incoming_messages.recv().await {
            // while let Some(message) = Rc::try_unwrap(boxed_bot).ok().unwrap().into_inner().incoming_messages.recv().await {
            // while let Some(message) = Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().rcv_helper().await {
            // while let Some(message) = Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().incoming_messages.recv().await {
            // let mut a = Arc::try_unwrap(boxed_bot.clone())
            //     .ok().unwrap()
            //     .into_inner()
            //     .ok().unwrap();
            // let a = Arc::clone(&boxed_bot).into_inner().unwrap().incoming_messages;
                // .into_inner()
                // .try_into().
                // .ok().unwrap();
            // while let Some(message) = a.lock().unwrap().incoming_messages.recv().await {
                // while let Some(message) = a.recv().await {
            // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap();
            // let mut a = Arc::try_unwrap(boxed_bot.clone())
            // .ok()
            // .unwrap();
            // .into_inner()
            // .get_mut()
            // .ok();
            // .unwrap();
            //let mut a = a.lock().unwrap();
            // let a = *a;
            // while let Some(message) = a.lock().ok().unwrap().incoming_messages.recv().await {
            // while let Some(message) = a.get_mut().expect("Error").incoming_messages.recv().await {
            //let tempbot = boxed_bot.clone();
            // while let Some(message) = Arc::try_unwrap(tempbot.clone()).ok().unwrap().into_inner().ok().unwrap().incoming_messages.recv().await {
            // while let Some(message) = Arc::try_unwrap(tempbot.clone()).ok().unwrap().incoming_messages.recv().await {
            // while let Some(message) = boxed_bot.to_owned().incoming_messages.recv().await {
            // while let Some(message) = self.incoming_messages.recv().await {
            // let a:Arc<RefCell<BotInstance>> = Arc::clone(&boxed_bot);
                // while let Some(message) = a.incoming_messages.recv().await {
            // let a = Arc::clone(&boxed_bot).into_inner();
            //  while let Some(message) = a.incoming_messages.recv().await {
            // let tempbot = boxed_bot.clone();
            // while let Some(message) = Arc::try_unwrap(tempbot.clone()).ok().unwrap().into_inner().incoming_messages.recv().await {

            // let tempbot = Arc::clone(&boxed_bot);

            // while let Some(message) = tempbot.lock().await.incoming_messages.recv().await {
            let a = bot.read().await;
            let mut a = a.incoming_messages.write().await;
            while let Some(message) = a.recv().await {
                
            // while let Some(message) = tempbot.into_inner().incoming_messages.recv().await {
            //while let Some(message) = boxed_bot.borrow().incoming_messages.recv().await {
                // // Below can be used to debug if I want to capture all messages
                // println!("Received message: {:?}", message);

                // let boxed_bot = Arc::new(self);
    
                match message {
                    ServerMessage::Notice(msg) => {
                        // if let Some(chnl) = msg.channel_login {
                        //     println!("NOTICE : (#{}) {}", chnl, msg.message_text);
                        // }
                        match &msg.channel_login {
                            Some(chnl) => println!("NOTICE : (#{}) {}", chnl, msg.message_text),
                            None => println!("NOTICE : {}", msg.message_text),
                        }
                    }
                    ServerMessage::Privmsg(msg) => {
                        println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);

                        println!("Privmsg section");

                        // b.listener_main_prvmsg(&msg);
                        // self.listener_main_prvmsg(&msg).await;
                        // bot.into_inner().listener_main_prvmsg(&msg).await;
                        //let bot = Rc::<RefCell<&BotInstance>>::clone(&bot);
                        
                        // bot.borrow().listener_main_prvmsg(&msg).await;
                        // let mut a = Rc::Clone(&bot);
                        // a.borrow_mut().listener_main_prvmsg(&msg).await;
                        // bot.borrow_mut().into_inner().listener_main_prvmsg(&msg).await;
                        // bot.listener_main_prvmsg(&msg).await;
                        // bot.lock().unwrap().listener_main_prvmsg(&msg).await;
                        // bot.borrow_mut().listener_main_prvmsg(&msg).await;
                        // Rc::clone(&boxed_bot).into_inner().listener_main_prvmsg(&msg).await;
                        // boxed_bot.borrow().listener_main_prvmsg(&msg).await;
                        // let bottemp = boxed_bot.borrow_mut();
                        // let a = **bottemp;
                        // Rc::try_unwrap(boxed_bot).ok().unwrap().into_inner().listener_main_prvmsg(&msg).await;
                        // Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().listener_main_prvmsg(&msg).await;
                        // Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().ok().unwrap().listener_main_prvmsg(&msg).await;
                        // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap();
                        // let mut a = a.lock().unwrap();  
                        // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap();
                        // a.listener_main_prvmsg(&msg).await;  

                        // (*a).listener_main_prvmsg(&msg).await;
                        // let a:Arc<RefCell<BotInstance>> = Arc::clone(&boxed_bot);
                        // a.into_inner().listener_main_prvmsg(&msg).await;
                        // let tempbot = boxed_bot.clone();
                        // Arc::try_unwrap(tempbot.clone()).ok().unwrap().into_inner().listener_main_prvmsg(&msg).await ;

                        // let tempbot = Arc::clone(&tempbot);
                        // // let a = tempbot.lock().await;
                        // tempbot.lock().await.listener_main_prvmsg(&msg).await;
                        // self.listener_main_prvmsg(&msg).await;
                        // bot.read().await.listener_main_prvmsg(&msg).await;
                        
                            // let a = bot.read().await;
                            // a.listener_main_prvmsg(&msg).await;
                            // a.listener_main_prvmsg(&msg).await;
                            // let a = bot.read().await;
                            BotInstance::listener_main_prvmsg(Arc::clone(&bot), &msg).await;
                            // let a = bot.read().await;
                            // a.lis
                        
                            

                        

                        //self.listener_main_prvmsg(&msg).await;

                        // - BotCommand listener should likely need to be called within the above


                    },
                    ServerMessage::Whisper(msg) => {
                        println!("(w) {}: {}", msg.sender.name, msg.message_text);
                    },
                    ServerMessage::Join(msg) => {
                        println!("JOINED: {}", msg.channel_login);
                    },
                    ServerMessage::Part(msg) => {
                        println!("PARTED: {}", msg.channel_login);
                    },
                    _ => {}
                }
            }
        });
    
    
    
    
    
        join_handle.await.unwrap();


    }



    pub fn get_botmodules(self) -> Arc<ModulesManager> {
        // let a = self.botmodules;
        // Arc::clone(&Arc::new(Mutex::new(self.botmodules)))
        // *self.botmodules
        self.botmodules

    } 

    // pub fn get_botactions(self:&Self) -> (Self,HashMap<botmodules::ModType,Vec<BotAction>>) {
    //     // self.get_botactions()
    //     // (*self,(*self).botmodules.rbotactions())
    //     (Self { bot_channel},(*self).botmodules.rbotactions())
    // }

    // pub fn get_botactions(&self) -> (Self,HashMap<botmodules::ModType,Vec<BotAction>>) {
    // pub fn get_botactions(&self) -> HashMap<botmodules::ModType,Vec<BotAction>> {
    //     // self.get_botactions()
    //     // (*self,(*self).botmodules.rbotactions())
    //     // (self,self.botmodules.rbotactions())
    //     // (*self).botmodules.rbotactions()
    //     // let a = (*self).botmodules.rbotactions();
    //     let a = 
    //     a 
    // }

    pub async fn get_botmgrs(self) -> BotManagers {
        // Arc::new(self.botmgrs)
        // Arc::clone(&Arc::new(Mutex::new(self.botmgrs)))
        let a = self.botmgrs;
        // let a = *a.lock().await;
        // let a = a.rIdentity();
        a
    }

    // pub  fn get_identity(self:&Self) -> (Self,IdentityManager) {
    pub  fn get_identity(&self) -> Arc<RwLock<IdentityManager>> {
        // // let a = self.botmgrs;
        // // Arc::clone(&Arc::new(Mutex::new(a.rIdentity())))
        // // let a = self.botmgrs;
        // // Arc::clone(&Arc::new(Mutex::new(a.rIdentity())))
        // let a = self.get_botmgrs().await;
        // let a = a.lock().await;
        // // let a = a.rIdentity();
        // let a = a.clone().identity;
        // a.clone()
        // let id = (*self).botmgrs.identity;
        // id
        Arc::clone(&self.botmgrs.identity)
    }

    
    // pub fn get_prefix(self) -> (Self,char) {
    pub fn get_prefix(&self) -> char {
        // self.prefix.to_string()
        // let a = self.prefix;
        // a.clone().to_string()
        // (self,self.prefix)
        
        (*self).prefix
    }

    // pub fn get_prefix(self:&Self) -> (Self,String) {
    //     (*self,(*self).prefix.to_string())
    // }
    // pub fn get_prefix(self:Self) -> (Self,String) {
    //     let str1 = self.prefix.to_string();
    //     (self,str1)
    // }

    // pub fn get_prefix(&self) -> String {
    //     // self.prefix.to_string()
    //     let a = self.prefix;
    //     a.clone().to_string()
    // }

    // pub fn get_prefix(self) -> (Self,String) {
    //     // self.prefix.to_string()
    //     // let a = self.prefix;
    //     // a.clone().to_string()
    //     (Self {
    //             prefix : self.prefix ,
    //             bot_channel : self.bot_channel  ,
    //             incoming_messages : self.incoming_messages ,
    //             botmodules : self.botmodules,
    //             twitch_oauth : self.twitch_oauth,
    //             bot_channels : self.bot_channels ,    
    //             // identity : IdentityManager::init(),
    //             botmgrs: self.botmgrs ,
    //         },
    //         self.prefix.to_string())
    // }

// -----------------
// PRIVATE FUNCTIONS 


    // async fn listener_main_prvmsg(&mut self,msg:PrivmsgMessage) -> () {
    // async fn listener_main_prvmsg(&mut self,msg:&PrivmsgMessage) -> () {
    // async fn listener_main_prvmsg(self,msg:&PrivmsgMessage) -> () {
    // async fn listener_main_prvmsg(self:Arc<Self>,msg:&PrivmsgMessage) -> () {
    pub async fn listener_main_prvmsg(bot:BotAR,msg:&PrivmsgMessage) -> () {
        println!(">> Inner listenermain_prvmsg()");

        // let a = a;
        // println!("(#{}) {}: {}", msg.channel_login, msg.sender.name, msg.message_text);
                            
        // // [ ] Need to run through all Listener Bodies for Enabled Modules for the context of the message (e.g., ModStatus is Enabled in the context for the channel)

        // let botmgr = Rc::new(&self.botmgrs);

        // let mut boxedbot = Rc::new(RefCell::new(self));
        // let boxed_bot = Rc::new(RefCell::new(self));
        // let boxed_bot = Arc::new(Mutex::new(self));
        // let boxed_bot = Arc::new(self);
        //let boxed_bot = Arc::clone(self);
        // let mut boxed_bot = Arc::new(RefCell::new(self));
        // let mut boxed_bot = Arc::new(RwLock::new(self));
        // let boxed_bot = Arc::new(RwLock::new(self));
        // let boxed_bot = Arc::new(Mutex::new(self));
        //let boxed_bot = Arc::new(Mutex::new(self));
        // let bot = Arc::new(RwLock::new(self));
        

        // for (_m,acts) in &self.botmodules.botactions {
        // for (_m,acts) in &self.botmodules.botactions {
            // for (_m,acts) in bot.into_inner().botmodules.botactions {
        // let mut bot = Rc::clone(&bot);
        // for (_m,acts) in bot.into_inner().botmodules.botactions {
            // for (_m,acts) in bot.into_inner().botmodules.botactions {
        // for (_m,acts) in Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().botmodules.botactions {
            // for (_m,acts) in Arc::try_unwrap(boxed_bot.clone()).ok() .unwrap().into_inner().ok().unwrap().botmodules.botactions {
        // for (_m,acts) in Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().botmodules.botactions {
        // for (_m,acts) in Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().botmodules.botactions {
            // let a = Arc::try_unwrap(boxed_bot).ok().unwrap().read().unwrap().botmodules.botactions
        // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap();
        // let b = a.read().unwrap();
        // for (_m,acts) in a.read().unwrap().botmodules.botactions {
        // for (_m,acts) in b.rbotmodules().botactions {
        // for (_m,acts) in b.rbotactions() {
            // for (_m,acts) in (*Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().read().unwrap()).rbotactions() {
        // let a = boxed_bot.clone().into_inner();
        // let a = boxed_bot.lock().await;
        //let a = a.lock().in
        // for (_m,acts) in self.rbotactions() {
        // for (_m,acts) in a.read().ok().unwrap().rbotactions() {
        // for (_m,acts) in a.into_inner().ok().unwrap().rbotactions() {

        // let bot = self;
        // let mut instr:char;

        // let hacts = self.get_botactions();
        // let hacts = boxed_bot.clone().lock().await.get_botactions();
        // let hacts = bot.read().await.get_botactions();
        let botlock = bot.read().await;
        let hacts = Arc::clone(&botlock.botmodules.botactions);
        // let hacts = hacts.read().await;
        let a = hacts.read().await;
        println!("hacts size : {}",(*a).len());

        println!(">> Inner listenermain_prvmsg() >> before for loop of bot actions");
        // println!(">> Inner listenermain_prvmsg() >> before for loop of bot actions : {:?}",*hacts);
        // let hacts = hacts
        // let l = *hacts;
        for (_m,acts) in &*hacts.read().await {
            
            println!(">> Inner listenermain_prvmsg() >> checking bot actions");
            

            // let bot = bot; 
            
            for a in acts {

                println!(">> Inner listenermain_prvmsg() >> checking bot actions >> 2");

                let _act = match a {

                    crate::core::botmodules::BotAction::C(c) => {
                        /* 
                        BotCommand handling -
                        - [x] Checks if the input message is a prefix with command name or alias
                        - [ ] Validate User can run based on identityModule(From_Bot)::can_user_run(
                                                        _usr:String,
                                                        _channelname:ChType,
                                                        _chat_badge:ChatBadge,
                                                        _cmdreqroles:Vec<UserRole>)
                        */

                        // for v in msg.message_text.split(" ") {
                        //     println!("args : {v}");
                        // }

                        println!("Reviewing internal commands");

                        let inpt = msg.message_text.split("\n").next().expect("ERROR during BotCommand");
                        let inpt = msg.message_text.split(" ").next().expect("ERROR during BotCommand");




                        // [x] Check if a bot command based on ...
                        //    [x] prefix + command

                        let mut confirmed_bot_command = false;
                        
                        // if inpt == self.prefix.to_string() + c.command.as_str() {
                        // if inpt == Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().prefix.to_string() + c.command.as_str() {
                            // let a = Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().prefix.to_string();
                            // let a = Arc::try_unwrap(boxed_bot.clone()).ok() .unwrap().into_inner().ok().unwrap().prefix.to_string();
                            // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().prefix.to_string();
                            // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().prefix.to_string();
                            // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap();
                            // let a = (*Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().read().unwrap());
                            // let a = (*Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().read().unwrap()).prefix.to_string();
                            // let a = self.prefix.to_string();
                        // let a = boxed_bot.clone();

                            // if inpt == a.into_inner().ok().unwrap().prefix.to_string() + c.command.as_str() {
                            // if inpt == a.into_inner().ok().unwrap().prefix.to_string() + c.command.as_str() 
                        // let a = boxed_bot.lock().await;
                        // 
                        // if inpt == a.into_inner().prefix.to_string() + c.command.as_str() {
                        // if inpt == a.get_prefix() + c.command.as_str() {
                        // if inpt == self.get_prefix() + c.command.as_str() {
                        // let instr = self.get_prefix();
                        // let instr = boxed_bot.clone().lock().await.get_prefix();
                        // let instr = bot.read().await.get_prefix();
                        let instr = bot.read().await.get_prefix();
                        if inpt == String::from(instr) + c.command.as_str() {
                            confirmed_bot_command = true;
                        } 

                        //    [x] prefix + alias
                        for alias in &c.alias {
                            // if inpt == self.prefix.to_string() + alias.as_str() {
                            // if inpt == Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().prefix.to_string() + alias.as_str() {
                            // 
                            // if inpt == Arc::try_unwrap(boxed_bot.clone()).ok() .unwrap().into_inner().ok().unwrap().prefix.to_string() + alias.as_str() {
                                // Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner()
                                // if inpt == Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().prefix.to_string() + alias.as_str() {
                                // if inpt == Arc::try_unwrap(boxed_bot).ok().unwrap().read().unwrap().prefix.to_string() + alias.as_str() {
                                // if inpt == self.prefix.to_string() + alias.as_str() {
                                // let a = boxed_bot.clone();
                                // let a = boxed_bot.lock().await;
                                // if inpt == a.into_inner().ok().unwrap().prefix.to_string() + alias.as_str() {
                            // if inpt == a.into_inner().prefix.to_string() + alias.as_str() {
                                // if inpt == a.get_prefix() + alias.as_str() {
                            // if inpt == self.get_prefix() + alias.as_str() {
                            // let instr = self.get_prefix();
                            // let instr = boxed_bot.clone().lock().await.get_prefix();
                            // let instr = bot.read().await.get_prefix();
                            let instr = bot.read().await.get_prefix();
                            if inpt == String::from(instr) + alias.as_str() {
                                confirmed_bot_command = true;
                            } 
                        }

                        if confirmed_bot_command {
                            println!("Confirmed bot command");
                            // self.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone());
                            
                            // [ ] Around here, validate if permissable before executing
                            // match self.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            //     Ok(Permissible::Allow) => c.execute(self.chat.clone(), msg.clone()).await,
                            //     Ok(Permissible::Block) => println!("User Not allowed to run command"),
                            //     _ => (),
                            // }

                            // match self.botmgrs.identity.to_owned().can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match self.botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match self.botmgrs.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone()) {

                            // let botref = Rc::clone(&botmgr);
                            // if let Rc(botmgr) = botref {
                            //     ()
                            // } 

                            // match self.botmgrs.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match boxed_bot.clone().into_inner().botmgrs.identity.clone().can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match Rc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner().botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            //let boxed_bot1 = Arc::clone(&boxed_bot);
                            //let a = boxed_bot1.into_inner().ok().unwrap();
                            // match boxed_bot1.into_inner().ok().unwrap().botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match Arc::try_unwrap(boxed_bot.clone())
                            //     .ok()
                            //     .unwrap().into_inner().ok().unwrap().botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // let a = Arc::try_unwrap(boxed_bot.clone()).ok() .unwrap().into_inner();
                            // let a = Arc::try_unwrap(boxed_bot.clone()).ok().unwrap();
                            // Arc::try_unwrap(boxed_bot.clone()).ok().unwrap().into_inner()
                            // match a.botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match Arc::try_unwrap(boxed_bot).ok().unwrap().read().unwrap().botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                                // match self.botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // match (boxed_bot.clone().into_inner().ok().unwrap()).botmgrs.identity.can_user_run_PRVMSG(&msg, c.required_roles.clone()) {
                            // let a = boxed_bot.clone();
                            // let a = boxed_bot.lock().await;
                            // // let a = a.read().ok().unwrap().botmgrs.identity;
                            // let a = a.get_identity();
                            // // let a = a.lock().await.can_user_run_PRVMSG(&msg, c.required_roles.clone()) ;
                            
                            // match a.lock().await.can_user_run_PRVMSG(&msg, c.required_roles.clone()).await {

                        
                            // let le = boxed_bot.lock().await;
                            // // let le = le.lock().await;
                            // let le = le.get_identity().await;
                            // let le = *le;
                            // let le = le.lock().await;
                            // let le = le.clone();
                            // let le = le.can_user_run_PRVMSG(&msg, c.required_roles.clone()).await;
                            // let le = self.get_identity().await.can_user_run_PRVMSG(&msg, c.required_roles.clone()).await;
                            // let le = self.botmgrs;
                            // let le = le.identity;
                            // let (bot,id) = self.get_identity();
                            // let id = boxed_bot.clone().lock().await.get_identity();
                            // let id = bot.read().await.get_identity();
                            // let id = Arc::clone(&self.botmgrs.identity);
                            // let id = id.write().await;
                            // let id = &(*self.get_identity());
                            println!("Going for botlock");
                            let botlock = bot.read().await;
                            println!("Going for identity");
                            let id = botlock.get_identity();
                            // let mut id = id.write().await;
                            // println!("Unlocking identity");
                            // let eval= id.can_user_run_PRVMSG(&msg, c.required_roles.clone()).await;
                            let eval = {
                                let mut id = id.write().await;
                                println!("Unlocking identity");
                                id.can_user_run_PRVMSG(&msg, c.required_roles.clone()).await
                            };
                            println!("Checking if permissible");
                            match eval {
                                // Ok(Permissible::Allow) => (),
                                Permissible::Allow => {
                                    println!("Executed as permissible");
                                    // c.execute(bot, msg.clone()).await;
                                    // if let bot = Rc::<RefCell<BotInstance>>::clone(*bot) {
                                    //     c.execute(bot, msg.clone()).await;
                                    // }
                                    // let boxed_bot = Arc::new(RwLock::new(self));
                                    // c.execute(boxed_bot.clone(), msg.clone()).await;
                                    // c.execute(self, msg.clone()).await;
                                    //let mut a = *self;
                                    // c.execute(self, msg.clone());
                                    // let a = self;
                                    // let a = Arc::clone(&self);
                                    let a = Arc::clone(&bot);
                                    // let a = Arc::clone(&bot);
                                    c.execute(a, msg.clone()).await;
                                    println!("exit out of execution");
                                    
                                }
                                Permissible::Block => {
                                    println!("User Not allowed to run command")
                                },
                                // _ => (),
                            };
                            };

                            // c.execute(self.chat.clone(), msg.clone()).await;
                            
                        }
                        None::<&PrivmsgMessage> // [ ] Command not confirmed?
                        None::<&PrivmsgMessage> // [ ] Command not confirmed?
                    },

                    crate::core::botmodules::BotAction::L(l) => {
                        // if let bot = Rc::clone(&bot) {
                        //     l.into_inner().execute(bot, msg.clone()).await
                        // }
                        //let bot = Rc::clone(&bot).into_inner();
                        // l.execute(boxed_bot.clone(), msg.clone()).await
                        // let boxed_bot = Arc::new(RwLock::new(self));
                        // l.execute(boxed_bot.clone(), msg.clone()).await;
                        // let a = Arc::clone(&self);
                        let a = Arc::clone(&bot);
                        l.execute(a, msg.clone()).await;
                    },

                    _ => (),
                };
            }
        };



        // // [ ] There should be a BotCommand Listener to check for prefixes ran

        println!("End of Separate Listener Main prvmsg");

        // self
        // bot

    }

    

}






// ======================================
// ======================================
// ======================================
// ======================================

// UNIT TEST MODULES





#[cfg(test)]
mod tests {
    fn always() {
        assert_eq!(1,1);
    }
}