/// 功能
pub mod action;
/// 插件
pub mod addon;
/// 模块
pub mod module;
/// 请求数据
pub mod request;
/// api清单
pub mod swagger;
/// 工具
pub mod tools;
#[cfg(feature = "pgsql")]
use log::warn;
use crate::action::Action;
use crate::addon::Addon;
use crate::module::Module;
use crate::request::Request;
use crate::tools::{Tools, ToolsConfig};
#[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql", feature = "pgsql"))]
use br_db::types::TableOptions;
use json::{array, object, JsonValue};
use lazy_static::lazy_static;
use log::{error, info};
use std::collections::HashMap;
use std::path::PathBuf;
use std::sync::{Mutex, OnceLock};
use std::{fs, thread};
use std::cell::RefCell;
use std::sync::LazyLock;

lazy_static! {
    /// 工具集合
    static ref PLUGIN_TOOLS: Mutex<HashMap<String,Tools>> =Mutex::new(HashMap::new());
    static ref CONFIG: Mutex<HashMap<String,JsonValue>> =Mutex::new(HashMap::new());
}
/// 全局监听线程
static GLOBAL_HANDLE: LazyLock<Mutex<HashMap<String, String>>> = LazyLock::new(|| Mutex::new(HashMap::new()));
/// 全局加载的插件清单
pub static GLOBAL_ADDONS: OnceLock<Vec<String>> = OnceLock::new();
/// 全局加载的模块清单
pub static GLOBAL_MODULE: OnceLock<Vec<String>> = OnceLock::new();
/// 全局加载的动作清单
pub static GLOBAL_ACTION: OnceLock<Vec<String>> = OnceLock::new();

thread_local! {
    /// 单线程全局变量
    static GLOBAL_DATA: RefCell<JsonValue> = RefCell::new(object!{});
}
/// 插件接口
pub trait Plugin {
    /// 加载插件
    fn addon(name: &str) -> Result<Box<dyn Addon>, String>;
    /// 加载模型
    fn module(name: &str) -> Result<Box<dyn Module>, String> {
        let (addon_name, module_name) = Self::split2(name)?;
        Self::addon(addon_name)?.module(module_name)
    }
    /// 加载动作
    fn action(name: &str) -> Result<Box<dyn Action>, String> {
        let (addon_name, module_name, action_name) = Self::split3(name)?;
        Self::addon(addon_name)?.module(module_name)?.action(action_name)
    }
    /// 内部api
    fn api_run(name: &str, request: Request) -> Result<JsonValue, String> {
        let (addon_name, module_name, action_name) = Self::split3(name)?;
        match Self::addon(addon_name)?.module(module_name)?.action(action_name)?.run(request) {
            Ok(e) => Ok(e.data),
            Err(e) => Err(e.message),
        }
    }
    /// 加载工具装置
    /// * path 配置文件路径
    fn load_tools(config: ToolsConfig) -> Result<(), String> {
        if PLUGIN_TOOLS.lock().unwrap().get("tools").is_none() {
            PLUGIN_TOOLS.lock().unwrap().insert("tools".into(), Tools::new(config)?);
        }
        Ok(())
    }
    /// 获取工具
    fn get_tools() -> Tools {
        let tools = PLUGIN_TOOLS.lock().unwrap();
        let tools = tools.get("tools").unwrap().clone();
        tools
    }
    /// 加载全局配置文件
    fn load_config(name: &str, config: JsonValue) {
        CONFIG.lock().unwrap().insert(name.into(), config.clone());
    }
    /// 根据API清单初始化数据库
    ///
    /// * path 插件目录
    #[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql", feature = "pgsql"))]
    fn init_db() -> Result<(), String> {
        info!("=============数据库更新开始=============");
        let mut tables = HashMap::new();
        // 生成数据库文件
        let sql = PathBuf::from("sql");

        // 删除目录
        match fs::remove_dir_all(sql.to_str().unwrap()) {
            Ok(_) => {}
            Err(e) => {
                #[cfg(feature = "pgsql")]
                warn!("目录删除失败: {e}");
                #[cfg(any(feature = "mysql", feature = "sqlite", feature = "mssql"))]
                error!("目录删除失败: {e}");
            }
        }

        // 创建目录
        match fs::create_dir_all(sql.to_str().unwrap()) {
            Ok(_) => {}
            Err(e) => error!("目录创建失败: {e}"),
        }

        let sql_file = sql.join("sql.json");
        let mut db_install = array![];

        for api_name in GLOBAL_MODULE.wait() {
            let mut addon = match Self::addon(api_name) {
                Ok(e) => e,
                Err(_) => {
                    continue;
                }
            };
            let module = match addon.module(api_name) {
                Ok(e) => e,
                Err(_) => {
                    continue;
                }
            };
            if !module.table() {
                continue;
            }
            if !tables.contains_key(module._table_name()) {
                tables.insert(module._table_name(), module);
            }
        }

        for (_, module) in tables.iter_mut() {
            let mut opt = TableOptions::default();

            let unique = module.table_unique().iter().map(|x| (*x).to_string()).collect::<Vec<String>>();
            let unique = unique.iter().map(|x| x.as_str()).collect::<Vec<&str>>();

            let index = module.table_index().iter().map(|x| x.iter().map(|&y| y.to_string()).collect::<Vec<String>>()).collect::<Vec<Vec<String>>>();
            let index = index.iter().map(|x| x.iter().map(|y| y.as_str()).collect::<Vec<&str>>()).collect::<Vec<Vec<&str>>>();


            opt.set_table_name(module._table_name());
            opt.set_table_title(module.title());
            opt.set_table_key(module.table_key());
            opt.set_table_fields(module.fields().clone());
            opt.set_table_unique(unique.clone());
            opt.set_table_index(index.clone());
            opt.set_table_partition(module.table_partition());
            opt.set_table_partition_columns(module.table_partition_columns());
            // 生成sql安装文件
            let sql = Self::get_tools().db.table(module._table_name()).fetch_sql().table_create(opt.clone());
            let update_sql = Self::get_tools().db.table(module._table_name()).fetch_sql().table_update(opt.clone());
            db_install.push(object! {
                    table:module._table_name(),
                    field:module.fields().clone(),
                    key:module.table_key(),
                    index:index.clone(),
                    unique:unique.clone(),
                    sql:sql,
                    update_sql:update_sql
                 }).unwrap();
            fs::write(sql_file.clone(), db_install.to_string()).unwrap();

            if Self::get_tools().db.table_is_exist(module._table_name()) {
                let res = Self::get_tools().db.table_update(opt);
                match res.as_i32().unwrap() {
                    -1 => {}
                    0 => {
                        info!("数据库更新情况: {} 失败", module._table_name());
                    }
                    1 => {
                        info!("数据库更新情况: {} 成功", module._table_name());
                    }
                    _ => {}
                }
            } else {
                let res = Self::get_tools().db.table_create(opt);
                info!("安装完成情况: {} {}", module._table_name(), res);
            }
        }
        info!("=============数据库更新完成=============");
        Ok(())
    }

    /// 全局插件监听入口
    fn handles() {
        let mut map = GLOBAL_HANDLE.lock().unwrap();
        for api in GLOBAL_MODULE.wait() {
            let mut module_name = match Self::module(api.as_str()) {
                Ok(e) => e,
                Err(e) => {
                    error!("插件: {api} 加载错误 {e}");
                    continue;
                }
            };
            if map.get(module_name.module_name()).is_none() {
                map.insert(module_name.module_name().to_string(), module_name.module_name().to_string());
                thread::spawn(move || module_name.handle());
            }
        }
    }
    /// 生成Swagger
    fn swagger(
        title: &str,
        description: &str,
        version: &str,
        uaturl: &str,
        produrl: &str,
        tags: JsonValue,
        paths: JsonValue,
    ) -> JsonValue {
        let info = object! {
            openapi:"3.0.0",
            info:{
                title:title,
                description:description,
                version:version
            },
            components: {
                securitySchemes: {
                    BearerToken: {
                        "type": "http",
                        "scheme": "bearer",
                        "bearerFormat": "Token"
                    }
                }
            },
            tags:tags,
            security: [
                {
                    "BearerToken": []
                }
            ],
            servers:[
                {
                    "url":uaturl,
                    "description": "测试地址"
                },
                {
                    "url":produrl,
                    "description": "正式地址"
                }
            ],
            paths:paths
        };
        info
    }
    /// 生成 api 列表
    fn generate_api_list(apipath: PathBuf, path: PathBuf, index: usize) -> Result<Vec<String>, String> {
        #[cfg(debug_assertions)]
        {
            let mut plugin_list = Vec::new();
            if path.is_dir() {
                let res = fs::read_dir(path);
                match res {
                    Ok(entries) => {
                        for entry in entries {
                            let entry = match entry {
                                Ok(e) => e,
                                Err(e) => {
                                    return Err(e.to_string())
                                }
                            };
                            let path = entry.path();
                            if path.is_dir() {
                                let res = Self::generate_api_list(
                                    apipath.clone(),
                                    path.to_str().unwrap().parse().unwrap(),
                                    index + 1,
                                )?;
                                plugin_list.extend(res);
                            } else if path.is_file() {
                                if path.to_str().unwrap().ends_with("mod.rs") {
                                    continue;
                                }
                                let addon = path.parent().unwrap().parent().unwrap().file_name().unwrap().to_str().unwrap();
                                let model = path.parent().unwrap().file_name().unwrap().to_str().unwrap();
                                let action = path.file_name().unwrap().to_str().unwrap().trim_end_matches(".rs");
                                let api = format!("{addon}.{model}.{action}");
                                match Self::action(api.as_str()) {
                                    Ok(e) => plugin_list.push(e.api()),
                                    Err(_) => continue
                                }
                            }
                        }
                    }
                    Err(e) => return Err(e.to_string())
                }
            }
            if index == 0 {
                fs::create_dir_all(apipath.clone().parent().unwrap()).unwrap();
                fs::write(apipath, JsonValue::from(plugin_list.clone()).to_string()).unwrap();
                info!("=============API数量: {} 条=============", plugin_list.len());
                Self::_load_apis(plugin_list.clone())?;
            }
            Ok(plugin_list)
        }
        #[cfg(not(debug_assertions))]
        {
            let apis = fs::read_to_string(apipath).unwrap();
            let apis = json::parse(&apis).unwrap();
            let apis = apis.members().map(|x| x.as_str().unwrap().to_string()).collect::<Vec<String>>();
            info!("=============API数量: {} 条=============", apis.len());
            Self::_load_apis(apis.clone())?;
            Ok(apis)
        }
    }
    /// 加载api清单
    fn _load_apis(apis: Vec<String>) -> Result<(), String> {
        let mut action_list = vec![];
        let mut module_list = vec![];
        let mut addons_list = vec![];
        for api in apis {
            let action = Self::action(api.as_str())?;
            action_list.push(action.api());
            if !module_list.contains(&action.module_name()) {
                module_list.push(action.module_name());
            }
            if !addons_list.contains(&action.addon_name()) {
                addons_list.push(action.addon_name());
            }
        }
        let _ = GLOBAL_ACTION.set(action_list);
        let _ = GLOBAL_MODULE.set(module_list);
        let _ = GLOBAL_ADDONS.set(addons_list);
        Ok(())
    }
    /// 设置全局变量
    fn set_global_data(key: &str, value: JsonValue) {
        GLOBAL_DATA.with(|data| {
            data.borrow_mut()[key] = value;
        });
    }
    /// 获取全局变量数据
    fn get_global_data() -> JsonValue {
        GLOBAL_DATA.with(|data| {
            data.borrow().clone()
        })
    }
    /// 获取全局变量指定字段数据
    fn get_global_data_key(key: &str) -> JsonValue {
        GLOBAL_DATA.with(|data| {
            data.borrow()[key].clone()
        })
    }
    /// 解析 "addon.module"（零分配）
    #[inline]
    fn split2(name: &str) -> Result<(&str, &str), String> {
        let t = name.split(".").collect::<Vec<&str>>();
        if t.len() < 2 {
            return Err(format!("模型格式不正确: {name}"));
        }
        Ok((t[0], t[1]))
    }

    /// 解析 "addon.module.action"（零分配）
    #[inline]
    fn split3(name: &str) -> Result<(&str, &str, &str), String> {
        if let Some((a, rest)) = name.split_once('.') {
            if let Some((b, c)) = rest.split_once('.') {
                if !a.is_empty() && !b.is_empty() && !c.is_empty() {
                    Ok((a, b, c))
                } else {
                    Err("动作格式不正确".to_string())
                }
            } else {
                Err("动作格式不正确".to_string())
            }
        } else {
            Err("动作格式不正确".to_string())
        }
    }
}
/// API 错误响应
#[derive(Debug, Clone)]
pub struct ApiResponse {
    pub types: ApiType,
    pub code: i32,
    pub message: String,
    pub data: JsonValue,
    pub success: bool,
    pub timestamp: i64,
}
impl ApiResponse {
    pub fn json(self) -> JsonValue {
        match self.types {
            ApiType::Json => object! {
                code: self.code,
                message: self.message,
                data: self.data,
                success: self.success
            },
            ApiType::Redirect => self.data,
            ApiType::Download => self.data,
            ApiType::Preview => self.data,
            ApiType::Txt => self.data,
            ApiType::Html => self.data,
        }
    }
    pub fn swagger(&mut self) -> JsonValue {
        let mut content = object! {};
        content[self.types.str().as_str()] = object! {};
        content[self.types.str().as_str()]["schema"]["type"] = if self.data.is_array() {
            "array"
        } else {
            "object"
        }.into();
        content[self.types.str().as_str()]["schema"]["properties"] = self.data.clone();

        content[self.types.str().as_str()]["schema"]["type"] = match content[self.types.str().as_str()]["schema"]["type"].as_str().unwrap() {
            "int" => "integer".into(),
            _ => content[self.types.str().as_str()]["schema"]["type"].clone(),
        };
        let data = object! {
            "description":self.message.clone(),
            "content":content
        };
        data
    }
    pub fn success(data: JsonValue, mut message: &str) -> Self {
        if message.is_empty() {
            message = "success";
        }
        Self {
            success: true,
            types: ApiType::Json,
            code: 0,
            message: message.to_string(),
            data,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    pub fn fail(code: i32, message: &str) -> Self {
        Self {
            types: ApiType::Json,
            code,
            message: message.to_string(),
            data: JsonValue::Null,
            success: false,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    pub fn error(data: JsonValue, message: &str) -> Self {
        Self {
            types: ApiType::Json,
            code: -1,
            message: message.to_string(),
            data,
            success: false,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    /// 重定向
    pub fn redirect(url: &str) -> Self {
        Self {
            types: ApiType::Redirect,
            code: 0,
            message: "".to_string(),
            data: url.into(),
            success: true,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    /// 下载
    pub fn download(filename: &str) -> Self {
        Self {
            types: ApiType::Download,
            code: 0,
            message: "".to_string(),
            data: filename.into(),
            success: true,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    /// 预览
    pub fn preview(filename: &str) -> Self {
        Self {
            types: ApiType::Preview,
            code: 0,
            message: "".to_string(),
            data: filename.into(),
            success: true,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    /// 文本
    pub fn txt(txt: &str) -> Self {
        Self {
            types: ApiType::Txt,
            code: 0,
            message: "".to_string(),
            data: txt.into(),
            success: true,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
    pub fn html(data: &str) -> Self {
        Self {
            types: ApiType::Html,
            code: 0,
            message: "".to_string(),
            data: data.into(),
            success: true,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
}
impl Default for ApiResponse {
    fn default() -> Self {
        Self {
            types: ApiType::Json,
            code: 0,
            message: "".to_string(),
            data: JsonValue::Null,
            success: false,
            timestamp: br_fields::datetime::Timestamp::timestamp(),
        }
    }
}
/// API 响应
#[derive(Debug, Clone)]
pub enum ApiType {
    /// JSON类型
    Json,
    /// 重定向
    /// (重定向地址: http://xxxxxx)
    Redirect,
    /// 下载
    /// (文件地址: 文件绝对地址)
    Download,
    /// 预览
    /// (文件地址: 文件绝对地址)
    Preview,
    /// TXT格式
    Txt,
    /// 返回网页
    Html,
}
impl ApiType {
    pub fn str(&mut self) -> String {
        match self {
            ApiType::Json => "application/json",
            ApiType::Redirect | ApiType::Download | ApiType::Preview => "text/html",
            ApiType::Txt => "text/plain",
            ApiType::Html => "text/html",
        }.to_string()
    }
}