#pragma once
//stl
#include <iostream>
#include <sstream>
#include <vector>
//boost
#include <boost/property_tree/ptree.hpp> 
#include <boost/property_tree/xml_parser.hpp>
//robotics
#include <robotics/linq.hpp>
//local
#include "../models/web_user_config_info.h"
#include "../models/web_after_config_info.h"
#include "../models/web_general_config_info.h"
/**
 * @brief 配置
 */
class xml_context {
public:
    /**
     * @brief 根据类型返回对应的 v3::linq_ptr<_Type> 实例，并可选择重置实例。
     * @tparam _Type 要获取的配置类型，可以是 web_user_config_info、web_after_config_info 或 web_general_config_info。
     * @param reset 是否重置实例，默认为 true。
     * @return 返回对应类型的 v3::linq_ptr<_Type> 引用。
     */
    template<typename _Type>
    static v3::linq_ptr<_Type>& from(bool reset = true) {
        if constexpr (std::is_same<web_user_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_user_config_->reset();
            }
            return *instance()->linq_user_config_;
        }
        else if constexpr (std::is_same<web_after_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_after_config_->reset();
            }
            return *instance()->linq_after_config_;
        }
        else if constexpr (std::is_same<web_general_config_info, _Type>::value) {
            if (reset) {
                instance()->linq_general_config_->reset();
            }
            return *instance()->linq_general_config_;
        }
    }
private:
    /**
     * @brief 返回 xml_context 的单例实例。
     * @return 指向全局唯一 xml_context 实例的指针。
     */
    static xml_context* instance() {
        static xml_context g_xml_context;
        return &g_xml_context;
    }
private:
    /**
     * @brief 初始化 xml_context 对象，加载配置并将配置列表交给 linq 管理，同时绑定配置变更事件处理函数。
     */
    xml_context() {
        load();
        //配置列表交给linq管理
        linq_user_config_.reset(new v3::linq_ptr<web_user_config_info>(user_config_list_));
        //绑定改变事件
        linq_user_config_->changed_bind(&xml_context::on_table_save<web_user_config_info>, this);

        //配置列表交给linq管理
        linq_after_config_.reset(new v3::linq_ptr<web_after_config_info>(after_config_list_));
        //绑定改变事件
        linq_after_config_->changed_bind(&xml_context::on_table_save<web_after_config_info>, this);

        //配置列表交给linq管理
        linq_general_config_.reset(new v3::linq_ptr<web_general_config_info>(general_config_list_));
        //绑定改变事件
        linq_general_config_->changed_bind(&xml_context::on_table_save<web_general_config_info>, this);
    }
    /**
     * @brief 加载并解析 XML 配置文件，将用户、授权和通用配置信息读取到对应的配置列表中。
     */
    void load() {
        boost::property_tree::ptree root;
        try {
            read_xml("./config/config.xml", root);
            //用户读取
            for (auto& it : root.get_child("root.users")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_user_config_info> item(new web_user_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->name = it.second.get<std::string>("<xmlattr>.name", "管理员");
                item->code = it.second.get<std::string>("<xmlattr>.code", "admin");
                item->password = it.second.get<std::string>("<xmlattr>.password", "123456");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                user_config_list_.push_back(item);
            }
            //授权读取
            for (auto& it : root.get_child("root.after")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_after_config_info> item(new web_after_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->value = it.second.get<std::string>("<xmlattr>.value", "");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                after_config_list_.push_back(item);
            }
			//通用配置读取
            for (auto& it : root.get_child("root.general")) {
                if (it.first != "item")
                    continue;
                std::shared_ptr<web_general_config_info> item(new web_general_config_info);
                item->id = it.second.get<int>("<xmlattr>.id", 0);
                item->modify_time = it.second.get<std::string>("<xmlattr>.modify_time", v3::datetime::current_datetime().to_string("yyyy-MM-dd HH:mm:ss"));
                item->key = it.second.get<int>("<xmlattr>.key", 1);
                item->value = it.second.get<std::string>("<xmlattr>.value", "");
                item->enable = it.second.get<bool>("<xmlattr>.enable", false);
                item->remarks = it.second.get<std::string>("<xmlattr>.remarks", "");
                general_config_list_.push_back(item);
            }
        }
        catch (std::exception const& ec) {
            LOG_ERROR << "读取xml配置异常" << ec;
        }
    }
    /**
     * @brief 保存当前的用户、授权用户和通用配置信息到 XML 文件中。
     */
    void save() {
        std::lock_guard<std::mutex> lock(mutex_);
        boost::property_tree::ptree root;
        try {
            //保存用户
            auto& user = root.add("root.users", "");
            for (auto& it : user_config_list_) {
                auto& item = user.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.name", it->name);
                item.put("<xmlattr>.code", it->code);
                item.put("<xmlattr>.password", it->password);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            //授权用户
            auto& after = root.add("root.after", "");
            for (auto& it : after_config_list_) {
                auto& item = after.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.value", it->value);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            //通用配置读取
            auto& general = root.add("root.general", "");
            for (auto& it : general_config_list_) {
                auto& item = general.add("item", "");
                item.put("<xmlattr>.id", it->id);
                item.put("<xmlattr>.modify_time", it->modify_time.to_string("yyyy-MM-dd HH:mm:ss"));
                item.put("<xmlattr>.key", it->key);
                item.put("<xmlattr>.value", it->value);
                item.put("<xmlattr>.enable", it->enable);
                item.put("<xmlattr>.remarks", it->remarks);
            }
            boost::property_tree::xml_writer_settings<std::string> settings(' ', 4);
            write_xml("./config/config.xml", root, std::locale(), settings);
        }
        catch (std::exception const& ec) {
            LOG_ERROR << ec;
        }
    }
private:
    /**
     * @brief 在表格保存操作中，根据条件决定是否执行保存。
     * @tparam _Table 表格数据的类型。
     * @param value 当前表格的值。
     * @param value_tmp 临时表格的值。
     * @param type 更改类型，指示表格发生了什么类型的更改（v3::linq_change_type）。
     * @param end 布尔值，指示是否为保存操作的结束阶段。
     */
    template<typename _Table>
    void on_table_save(_Table const& value, _Table const& value_tmp, v3::linq_change_type type, bool end) {
        if (end) {
            save();
        }
    }
private:
    std::mutex												        mutex_;
    std::vector<std::shared_ptr<web_user_config_info>>	            user_config_list_;
    std::shared_ptr<v3::linq_ptr<web_user_config_info>>	            linq_user_config_;
    std::vector<std::shared_ptr<web_after_config_info>>	            after_config_list_;
    std::shared_ptr<v3::linq_ptr<web_after_config_info>>	        linq_after_config_;
    std::vector<std::shared_ptr<web_general_config_info>>	        general_config_list_;
    std::shared_ptr<v3::linq_ptr<web_general_config_info>>	        linq_general_config_;
    
};