use std::error::Error;

use std::collections::HashMap;


/*

ModulesManager is made of modulesdb , a HashMap of BotModules with a Vector representing their enabled/disabled status based on channel and instance

Example
    {
        BotModule("Experiments") , [Enabled(Channel("modulatingforce")) , Disabled(Channel("modulatingforce")), Enabled(Instance)]
    }

*/

#[derive(Debug, PartialEq, Eq, Hash)]
pub enum ModType {
    BotModule(String),
}
    
pub use ModType::BotModule;

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


pub use ChType::Channel;


#[derive(Debug)]
enum StatusLvl {
    Instance,
    Ch(ChType),
}

#[derive(Debug)]
pub enum ModStatusType {
    Enabled(StatusLvl),
    Disabled(StatusLvl),
}
    
// pub use EnType::Enabled;

#[derive(Debug)]
enum BotAction {
	C(BotCommand),
	L(Listener),
	R(Routine),
}
#[derive(Debug)]
struct BotCommand {}

#[derive(Debug)]
struct Listener {
    module : ModType,
    name : String,
    // exec_body : fn,
    help : String
}

#[derive(Debug)]
struct Routine {}


#[derive(Debug)]
pub struct ModulesManager {
    statusdb: HashMap<ModType,Vec<ModStatusType>>,
    botactions: HashMap<ModType,Vec<BotAction>>, 
}

impl ModulesManager {

    pub fn init() -> ModulesManager {

        // initializes the modulers manager 
        // Ideally, this should have added known modules based on
        // directory structure and API user recommendations

        let mut m = HashMap::new();
        let mut act = HashMap::new();

        // -- some processing including adding into the hashmap

        // let newmodule = BotModule(String::from("GambaCore"));

        let newlistener = Listener {
            module : BotModule(String::from("experiments").to_owned()),
            name : String::from("socklistener"),
            help : String::from("This will listen and react to sock randomly"),
        };


        // As a Demonstration, the listener's Module is added and Enabled at Instance level
        let statusvector = m
            .entry(BotModule(String::from("experiments")))
            .or_insert(Vec::new());

        statusvector.push(ModStatusType::Enabled(StatusLvl::Instance));

        let modactions = act
            .entry( BotModule(String::from("experiments")))
            .or_insert(Vec::new());

        modactions.push(BotAction::L(newlistener));


        let mgr = ModulesManager {
            statusdb : m,
            botactions : act,
        };

        println!(">> Modules Manager : {:?}",mgr);

        mgr 
    } 

    pub fn modstatus(&self, _:ModType, _:ChType) -> ModStatusType {
        // Example usage : botmanager.modstatus(
        //     BotModule("GambaCore"),
        //     Channel("modulatingforce")
        // ) 
        // - The ModStatusType checks in the context of the given channel , 
        //  but also validates based on wheher the module is disabled at a bot instance
        //  level as well
        ModStatusType::Enabled(StatusLvl::Instance)
    }


    pub fn togglestatus(&self, _:ModType, _:ChType) -> ModStatusType {
        // enables or disables based on current status
        ModStatusType::Enabled(StatusLvl::Instance)
    }


    pub fn setstatus(&self, _:ModType, _:ModStatusType) -> Result<&str,Box<dyn Error>> {
        // sets the status based given ModSatusType
        // e.g., b.setstatus(BodModule("GambaCore"), Enabled(Channel("modulatingforce"))).expect("ERROR")
        Ok("")
    }


    fn statuscleanup(&self,chnl:Option<ChType>) -> () {
        // internal cleans up statusdb . For example : 
        // - remove redudancies . If we see several Enabled("m"), only keep 1x
        // - Clarify Conflict. If we see Enabled("m") and Disabled("m") , we remove Enabled("m") and keep Disabled("m")
        // the IDEAL is that this is ran before every read/update operation to ensure quality
        // Option<ChType> can pass Some(Channel("m")) (as an example) so statuscleanup only works on the given channel
        // Passing None to chnl may be a heavy operation, as this will review and look at the whole table
        ()
    }



}