Documentation
use std::path::PathBuf;
use std::sync::{RwLock};
use json::{JsonValue, object};
use serde::{Deserialize, Serialize};
use crate::aliyun::Aliyun;
pub use crate::config::Config;
use crate::tencent::Tencent;
use once_cell::sync::Lazy;
static GLOBAL_CONFIG: Lazy<RwLock<Config>> = Lazy::new(|| {
    RwLock::new(Config::default())
});

mod aliyun;
mod tencent;
mod config;

#[derive(Clone)]
pub enum Oss {
    Aliyun(Aliyun),
    Tencent(Tencent),
    None,
}
impl Oss {
    /// 配置文件模式
    pub fn new(config: Config) -> Result<Self, String> {
        {
            let mut data = GLOBAL_CONFIG.write().unwrap();
            data.clone_from(&config);
        }
        let config = GLOBAL_CONFIG.read().unwrap();
        let connection = config.connections.get(config.default.as_str()).unwrap().clone();
        match connection.channel {
            Channel::Aliyun => Ok(Oss::Aliyun(Aliyun::new(connection))),
            Channel::Tencent => Ok(Oss::Tencent(Tencent::new(connection))),
            Channel::None => Ok(Oss::None),
        }
    }
    /// 非配置文件模式
    pub fn create(name: &str, connection: Connection) -> Result<Self, String> {
        {
            let mut data = GLOBAL_CONFIG.write().unwrap();
            if !data.connections.contains_key(name) {
                data.connections.insert(name.to_string(), connection);
            }
            data.default = name.to_string();
        }
        let config = GLOBAL_CONFIG.read().unwrap();
        let connection = config.connections.get(config.default.as_str()).unwrap().clone();
        match connection.channel {
            Channel::Aliyun => Ok(Oss::Aliyun(Aliyun::new(connection))),
            Channel::Tencent => Ok(Oss::Tencent(Tencent::new(connection))),
            Channel::None => Err("mode not supported!".to_string()),
        }
    }

    pub fn connections(&mut self) -> JsonValue {
        let mut connections = vec![];
        let data = GLOBAL_CONFIG.read().unwrap();
        for (item, mut value) in data.connections.clone() {
            if value.channel.str().is_empty() {
                continue;
            }
            let mut t = value.json();
            t["name"] = item.into();
            connections.push(t);
        }
        connections.into()
    }
}
impl OssMode for Oss {
    /// 推送
    /// path 地址路径
    fn upload(&mut self, dirname: &str, file: PathBuf, content_type: &str) -> Result<(String, String), String> {
        let path = dirname_handle(dirname);
        match self {
            Oss::Aliyun(e) => e.upload(path.as_str(), file, content_type),
            Oss::Tencent(e) => e.upload(path.as_str(), file, content_type),
            Oss::None => Err("upload 错误".to_string())
        }
    }
    fn download(&mut self, dirname: &str, key: &str) -> Result<(String, String, String, Vec<u8>), String> {
        let path = dirname_handle(dirname);
        match self {
            Oss::Aliyun(e) => e.download(path.as_str(), key),
            Oss::Tencent(e) => e.download(path.as_str(), key),
            Oss::None => Err("download 错误".to_string())
        }
    }

    fn query(&mut self, dirname: &str, key: &str) -> Result<(String, String), String> {
        let path = dirname_handle(dirname);
        match self {
            Oss::Aliyun(e) => e.query(path.as_str(), key),
            Oss::Tencent(e) => e.query(path.as_str(), key),
            Oss::None => Err("query 错误".to_string())
        }
    }

    /// 删除
    fn del(&mut self, dirname: &str, key: &str) -> Result<bool, String> {
        let path = dirname_handle(dirname);
        match self {
            Oss::Aliyun(e) => e.del(path.as_str(), key),
            Oss::Tencent(e) => e.del(path.as_str(), key),
            Oss::None => Err("del 错误".to_string())
        }
    }
}
fn dirname_handle(dirname: &str) -> String {
    if dirname.is_empty() {
        "/".to_string()
    } else {
        let tt = dirname.trim_start_matches("/").trim_end_matches("/").to_string();
        format!("/{tt}/")
    }
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct Connection {
    pub channel: Channel,
    /// 腾讯云是地域信息
    /// Endpoint以杭州为例,其它Region请按实际情况填写。 https://oss-cn-hangzhou.aliyuncs.com
    pub endpoint: String,
    pub access_key_id: String,
    pub access_key_secret: String,
    pub bucket_name: String,
}

impl Default for Connection {
    fn default() -> Self {
        Self {
            channel: Channel::None,
            endpoint: "".to_string(),
            access_key_id: "".to_string(),
            access_key_secret: "".to_string(),
            bucket_name: "".to_string(),
        }
    }
}

impl Connection {
    pub fn json(&mut self) -> JsonValue {
        let mut data = object! {};
        data["channel"] = self.channel.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(data: JsonValue) -> Connection {
        Self {
            channel: Channel::from(data["channel"].as_str().unwrap_or("")),
            endpoint: data["endpoint"].to_string(),
            access_key_id: data["access_key_id"].to_string(),
            access_key_secret: data["access_key_secret"].to_string(),
            bucket_name: data["bucket_name"].to_string(),
        }
    }
}


#[derive(Clone, Debug, Serialize, Deserialize)]
pub enum Channel {
    Aliyun,
    Tencent,
    None,
}

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


pub trait OssMode {
    /// 上传
    /// # 参数
    /// - dirname 远程桶目录
    /// - `file`:要上传的本地文件路径(`PathBuf`)
    /// - `content_type`:该文件的 MIME 类型(如 `application/octet-stream`、`image/png`)
    ///
    /// # 返回值
    /// - `Ok((key, url))`:上传成功,返回对应的 key(存储标识)和请求 URL(资源访问地址)
    /// - `Err(error)`:上传失败,返回错误信息
    fn upload(&mut self, dirname: &str, file: PathBuf, content_type: &str) -> Result<(String, String), String>;
    /// 下载
    /// # 返回值
    /// - `Ok((key, url,content_type,data))`:下载成功,返回对应的 key(存储标识)和请求 URL(资源访问地址)
    /// - `Err(error)`:下载失败,返回错误信息
    fn download(&mut self, dirname: &str, key: &str) -> Result<(String, String, String, Vec<u8>), String>;
    /// 查询
    /// # 返回值
    /// - `Ok((key, url,content_type,data))`:下载成功,返回对应的 key(存储标识)和请求 URL(资源访问地址)
    /// - `Err(error)`:下载失败,返回错误信息
    fn query(&mut self, dirname: &str, key: &str) -> Result<(String, String), String>;
    /// 删除
    fn del(&mut self, dirname: &str, key: &str) -> Result<bool, String>;
}