use std::collections::HashMap;
use std::fs;
use json::{JsonValue, object};
use crate::mode::OssMode;

mod mode;

#[derive(Clone)]
pub struct Oss {
    default: String,
    connections: HashMap<String, Connection>,
}
impl Default for Oss {
    fn default() -> Self {
        let mut connections = HashMap::new();
        connections.insert("my_name".to_string(), Connection::new());
        Self {
            default: "my_name".to_string(),
            connections,
        }
    }
}
impl Oss {
    pub fn new(path: &str) -> Self {
        let text = fs::read_to_string(path).unwrap_or("".to_string());
        let json = {
            if text.is_empty() {
                let mut def = Oss::default();
                let json = def.json();
                fs::write(path, json.to_string()).unwrap();
                json
            } else {
                json::parse(&text.clone()).unwrap()
            }
        };
        Oss::from(json)
    }
    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::new().from(value.clone()).clone();
            connections.insert(key.to_string(), connection.clone());
        }
        Self {
            default,
            connections,
        }
    }
    fn 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 Self {
        self.default = name.to_string();
        self
    }

    /// 推送
    /// path 地址路径
    pub fn put(&mut self, filename: &str, path: &str) -> Result<String, String> {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).put(filename, path)
        }
    }
    /// 获取
    pub fn get(&mut self, name: &str) -> Result<Vec<u8>, String> {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).get(name)
        }
    }
    /// 删除
    pub fn del(&mut self, name: &str) -> Result<bool, String> {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).del(name)
        }
    }
    /// 判断文件是否存在
    pub fn get_head(&mut self, name: &str) -> Result<String, String> {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).get_head(name)
        }
    }
    pub fn get_head_meta(&mut self, name: &str) -> Result<JsonValue, String> {
        match self.connections.get(&*self.default).unwrap().mode {
            Mode::Aliyun => mode::aliyun::Aliyun::new(self.connections.get(&*self.default).unwrap().clone()).get_head_meta(name)
        }
    }
}


#[derive(Clone)]
pub struct Connection {
    // Endpoint以杭州为例，其它Region请按实际情况填写。 https://oss-cn-hangzhou.aliyuncs.com
    pub endpoint: String,
    pub access_key_id: String,
    pub access_key_secret: String,
    pub mode: Mode,
    pub bucket_name: String,
}

impl Default for Connection {
    fn default() -> Self {
        Self::new()
    }
}

impl Connection {
    pub fn new() -> Connection {
        Self {
            mode: Mode::Aliyun,
            endpoint: "".to_string(),
            access_key_id: "".to_string(),
            access_key_secret: "".to_string(),
            bucket_name: "".to_string(),
        }
    }
    pub fn to_json(&mut self) -> JsonValue {
        let mut data = object! {};
        data["mode"] = self.mode.to_str().into();
        data["endpoint"] = self.endpoint.clone().into();
        data["access_key_id"] = self.access_key_id.clone().into();
        data["access_key_secret"] = self.access_key_secret.clone().into();
        data["bucket_name"] = self.bucket_name.clone().into();
        data
    }
    pub fn from(&mut self, data: JsonValue) -> &mut Connection {
        self.mode = Mode::from(data["mode"].as_str().unwrap());
        self.endpoint = data["endpoint"].to_string();
        self.access_key_id = data["access_key_id"].to_string();
        self.access_key_secret = data["access_key_secret"].to_string();
        self.bucket_name = data["bucket_name"].to_string();
        self
    }
}


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

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