#[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
use std::fs;
use std::sync::mpsc::{Sender, Receiver};

use json::{JsonValue, object};

#[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
use br_db::Db;

#[cfg(any(feature = "cache"))]
use br_cache::Cache;
#[cfg(any(feature = "kafka"))]
use br_kafka::Kafka;

use lazy_static::lazy_static;
use std::sync::{Arc, Mutex};
use std::collections::HashMap;
use std::path::PathBuf;
#[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
use log::{error};

use crate::config::Config;

pub mod addon;
pub mod model;
pub mod action;
pub mod config;
#[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
pub mod table;

/// 集合工具
#[derive(Clone)]
pub struct Tools {
    #[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
    pub db: Db,
    #[cfg(any(feature = "cache"))]
    pub cache: Cache,
    #[cfg(any(feature = "kafka"))]
    pub kafka: Kafka,

    pub config: Config,
}

impl Tools {
    pub fn new(config_dir: &str) -> Result<Self, String> {
        let config = match Config::new(PathBuf::from(config_dir)) {
            Ok(e) => e,
            Err(e) => {
                return Err(e);
            }
        };

        let mut that = Self {
            #[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
            db: Db::None,
            #[cfg(any(feature = "cache"))]
            cache: Cache::None,
            #[cfg(any(feature = "kafka"))]
            kafka: Kafka::connect(object! {}),
            config,
        };

        #[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
        that.set_db(format!("{}", that.config.config_dir.join("db.json").to_str().unwrap()).as_str());
        #[cfg(any(feature = "cache"))]
        that.set_cache(format!("{}", that.config.config_dir.join("cache.json").to_str().unwrap()).as_str());
        #[cfg(any(feature = "kafka"))]
        that.set_kafka(format!("{}", that.config.config_dir.join("kafka.json").to_str().unwrap()).as_str());

        PLUGIN_TOOLS.lock().unwrap().insert("tools".to_string(), that.clone());
        Ok(that)
    }
    #[cfg(any(feature = "mysql", feature = "mssql", feature = "sqlite"))]
    pub fn set_db(&mut self, config_filename: &str) -> &mut Self {
        match Db::load(config_filename) {
            Ok(db) => {
                self.db = db;
                PLUGIN_TOOLS.lock().unwrap().insert("tools".to_string(), self.clone());
            }
            Err(e) => {
                error!("数据库配置文件错误: {}",e.to_string());
            }
        }
        self
    }
    #[cfg(any(feature = "cache"))]
    pub fn set_cache(&mut self, config_path: &str) -> &mut Self {
        let rs = fs::read_to_string(config_path).unwrap();
        let json_data = json::parse(&*rs).unwrap();
        self.cache = Cache::new(json_data).unwrap_or_else(|_| Cache::None);
        PLUGIN_TOOLS.lock().unwrap().insert("tools".to_string(), self.clone());
        self
    }
    #[cfg(any(feature = "kafka"))]
    pub fn set_kafka(&mut self, config_path: &str) -> &mut Self {
        let conf = match fs::read_to_string(config_path) {
            Ok(e) => e,
            Err(_) => {
                error!("kafka配置文件不存在,未启动");
                return self;
            }
        };
        match json::parse(conf.as_str()) {
            Ok(config) => {
                self.kafka = Kafka::connect(config);
                PLUGIN_TOOLS.lock().unwrap().insert("tools".to_string(), self.clone());
            }
            Err(e) => {
                error!("kafka配置文件错误: {}", e.to_string());
            }
        }
        self
    }
}

lazy_static! {
    /// 工具集合
    pub static ref PLUGIN_TOOLS: Mutex<HashMap<String,Tools>> =Mutex::new(HashMap::new());
    pub static ref PLUGIN_WS_TX: Mutex<HashMap<String,Sender<JsonValue>>> =Mutex::new(HashMap::new());
    pub static ref PLUGIN_WS_RX: Mutex<HashMap<String,Arc<Mutex<Receiver<JsonValue>>>>> =Mutex::new(HashMap::new());
}


/// 按钮颜色
pub enum BtnColor {
    Red,
    Blue,
    Yellow,
    Green,
}

impl BtnColor {
    fn from(self) -> &'static str {
        match self {
            BtnColor::Red => "red",
            BtnColor::Blue => "blue",
            BtnColor::Yellow => "yellow",
            BtnColor::Green => "green",
        }
    }
}

/// 按钮模式
pub enum BtnMode {
    Form,
    FormDownload,
    Url,
    Api,
    Download,
    Path,
}

impl BtnMode {
    fn from(self) -> &'static str {
        match self {
            BtnMode::Form => "form",
            BtnMode::FormDownload => "form_download",
            BtnMode::Api => "api",
            BtnMode::Download => "download",
            BtnMode::Url => "url",
            BtnMode::Path => "path",
        }
    }
}

/// 返回响应
#[derive(Clone, Debug)]
pub struct Response(&'static str, JsonValue);

impl Response {
    /// 获取消息
    pub fn get_msg(self) -> &'static str {
        self.0
    }
    /// 获取数据
    pub fn get_data(self) -> JsonValue {
        self.1
    }
    /// 获取业务数据
    pub fn get_data_data(self) -> JsonValue {
        self.get_data()["data"].clone()
    }
    /// 获取业务反馈编号
    pub fn get_data_code(self) -> i32 {
        self.get_data()["code"].as_i32().unwrap()
    }
    /// 获取业务提示消息
    pub fn get_data_msg(self) -> String {
        self.get_data()["msg"].to_string()
    }
    pub fn into(self) -> (&'static str, JsonValue) {
        return (self.0, self.1);
    }
    /// 成功
    pub fn success(data: JsonValue, msg: &str) -> Self {
        let data = object! {code: 0,data:data,msg: msg.to_string()};
        Self("json", data)
    }
    /// 失败
    pub fn fail(msg: &str) -> Self {
        let data = object! {
            code: -1,
            msg: msg.to_string()
        };
        Self("json", data)
    }
    /// 失败
    pub fn error(code: usize, msg: String) -> Self {
        let data = object! {
            code: code,
            msg: msg
        };
        Self("json", data)
    }

    /// 通知消息
    pub fn notify(msg: &str, btn_name: &str, path: &str) -> Self {
        let data = object! {
            code: 0,
            msg: msg.to_string(),
            btn_name:btn_name,
            path:path
        };
        Self("json", data)
    }

    /// 登陆
    pub fn login(msg: &str) -> Self {
        let data = object! {code: 1000,msg: msg.to_string(),};
        Self("json", data)
    }
    /// 下载
    pub fn download(filename: &str) -> Self {
        Self("download", filename.into())
    }
    /// 下载并删除文件和所在文件夹
    pub fn download_delete_dir(filename: &str) -> Self {
        Self("download_delete_dir", filename.into())
    }
    /// 重定向
    pub fn redirect(url: &str) -> Self {
        Self("url", url.into())
    }
}