use std::collections::HashMap;
use std::fs;
use json::{JsonValue, object};
use crate::imap::Imap;
use crate::pop3::Pop3;
use crate::smtp::Smtp;

#[cfg(any(feature = "default", feature = "pop3"))]
mod pop3;
#[cfg(any(feature = "default", feature = "imaps"))]
mod imap;
#[cfg(any(feature = "default", feature = "smtp"))]
mod smtp;
#[derive(Clone)]
pub struct Mail {
    default: String,
    connections: HashMap<String, Connection>,
}

impl Mail {
    pub fn new(path: &str) -> Self {
        let text = fs::read_to_string(path).unwrap_or("".to_string());
        let json = {
            if text == "" {
                let mut def = Mail::default();
                let json = def.to_json();
                fs::write(path, json.to_string()).unwrap();
                json
            } else {
                json::parse(&*text.clone()).unwrap()
            }
        };
        Mail::from(json)
    }

    // 从数据库获取账号并创建链接的方法
    pub fn new_from_db(data: JsonValue) -> Self {
        Mail::from(data)
    }

    pub fn from(data: JsonValue) -> Self {
        let default = data["default"].to_string();
        let mut connections = HashMap::new();
        for (key, value) in data["connections"].entries() {
            let connection = Connection::default().from(value.clone()).clone();
            connections.insert(key.to_string(), connection.clone());
        }
        Self {
            default,
            connections,
        }
    }
    pub fn default() -> Self {
        let mut connections = HashMap::new();
        connections.insert("my_name".to_string(), Connection::default());
        Self {
            default: "my_name".to_string(),
            connections,
        }
    }
    fn to_json(&mut self) -> JsonValue {
        let mut data = object! {};
        data["default"] = self.default.clone().into();
        let mut connections = object! {};
        for (name, connection) in self.connections.iter_mut() {
            connections[name.clone()] = connection.to_json().clone();
        }
        data["connections"] = connections;
        data
    }
    pub fn connection(&mut self, name: &str) -> &mut Mail {
        self.default = name.to_string();
        self
    }
    #[cfg(any(feature = "default", feature = "imaps"))]
    pub fn imap(&mut self) -> Imap {
        let data = self.connections.get(&*self.default).unwrap().clone();
        Imap::new(data.clone())
    }
    #[cfg(any(feature = "default", feature = "pop3"))]
    pub fn pop3(&mut self) -> Pop3 {
        let data = self.connections.get(&*self.default).unwrap().clone();
        Pop3::new(data.clone())
    }
    #[cfg(any(feature = "default", feature = "smtp"))]
    pub fn smtp(&mut self) -> Smtp {
        let data = self.connections.get(&*self.default).unwrap().clone();
        Smtp::new(data.clone())
    }
}


#[derive(Clone)]
pub enum Mode {
    QQ
}

impl Mode {
    pub fn to_str(&mut self) -> &'static str {
        match self {
            Mode::QQ => "qq",
        }
    }
    pub fn from(name: &str) -> Self {
        match name {
            "qq" => Mode::QQ,
            _ => Mode::QQ
        }
    }
}

#[derive(Clone)]
pub enum Protocol {
    Pop3,
    Imap,
    Smtp,
}

impl Protocol {
    pub fn to_str(&mut self) -> &'static str {
        match self {
            Protocol::Pop3 => "pop3",
            Protocol::Imap => "imap",
            Protocol::Smtp => "smtp"
        }
    }
    pub fn from(name: &str) -> Self {
        match name {
            "pop3" => Protocol::Pop3,
            "imap" => Protocol::Imap,
            "smtp" => Protocol::Smtp,
            _ => Protocol::Imap
        }
    }
}

#[derive(Clone)]
pub struct Connection {
    host: String,
    port: String,
    name: String,
    mail: String,
    pass: String,
    protocol: Protocol,
}

impl Connection {
    pub fn default() -> Connection {
        Self {
            host: "".to_string(),
            port: "".to_string(),
            name: "".to_string(),
            mail: "".to_string(),
            pass: "".to_string(),
            protocol: Protocol::Imap,
        }
    }
    pub fn to_json(&mut self) -> JsonValue {
        let mut data = object! {};
        data["host"] = self.host.clone().into();
        data["port"] = self.port.clone().into();
        data["name"] = self.name.clone().into();
        data["pass"] = self.pass.clone().into();
        data["mail"] = self.mail.clone().into();
        data["protocol"] = self.protocol.to_str().into();
        data
    }
    pub fn from(&mut self, data: JsonValue) -> &mut Connection {
        self.protocol = Protocol::from(data["protocol"].as_str().unwrap());
        self.host = data["host"].to_string();
        self.port = data["port"].to_string();
        self.name = data["name"].to_string();
        self.pass = data["pass"].to_string();
        self.mail = data["mail"].to_string();
        self
    }
}