#pragma once
#include <asio2/asio2.hpp>
#include <robotics/logger.hpp>
#include <robotics/utils.hpp>
#include "../xml/xml_context.hpp"
#include "../models/web_response_info.h"
#include "../models/web_message_info.h"
#include "../models/web_sync_alarm_info.h"

using namespace robotics;

namespace utils {
	enum class http_type_enum {
		post,
		get
	};

	struct http_request {
		std::string get(std::string const& url, std::map<std::string, std::string> const& headers = {}) {
			http::web_request request = http::make_request(url);
			request.method(http::verb::get);
			for (auto& [key,value] : headers) {
				request.set(key, value);
			}
			request.prepare_payload();
			auto response = asio2::http_client::execute(request);
			if (asio2::get_last_error()) {
				throw std::runtime_error("HTTP request failed: " + v3::utils::gbk_to_utf8(asio2::get_last_error_msg()));
			}
			else if (response.result() != http::status::ok) {
				throw std::runtime_error("HTTP request failed: " + std::to_string((int)response.result()));
			}
			return response.body();
		}
		std::string post(std::string const& url, std::string const& data,std::map<std::string, std::string> const& headers = {}) {
			http::web_request request = http::make_request(url);
			request.method(http::verb::post);
			for (auto& [key, value] : headers) {
				request.set(key, value);
			}
			request.body() = data;
			request.prepare_payload();
			auto response = asio2::http_client::execute(request);
			if (asio2::get_last_error()) {
				throw std::runtime_error("HTTP request failed: " + asio2::get_last_error_msg());
			}
			else if (response.result() != http::status::ok) {
				throw std::runtime_error("HTTP request failed: " + std::to_string((int)response.result()));
			}
			return response.body();
		}
	};

	struct web_http {
		template<http_type_enum _Type,typename _Ret>
		_Ret request(std::string const& url, std::string const& data, std::map<std::string, std::string> const& headers = {}) {
			static_assert(!std::is_same<_Ret, std::string>::value, "type err");
			std::string json = request<_Type>(url, data, headers);
			LOG_INFO << "http响应:" << json;
			return response<_Ret>(json);
		}

		template<http_type_enum _Type, typename _Ret>
		_Ret request(std::string const& url, std::map<std::string, std::string> const& headers = {}) {
			static_assert(!std::is_same<_Ret, std::string>::value, "type err");
			std::string json = request<_Type>(url, "", headers);
			LOG_INFO << "http响应:" << json;
			return response<_Ret>(json);
		}

		template<http_type_enum _Type>
		std::string request(std::string const& url, std::string const& data, std::map<std::string, std::string> const& headers = {}) {
			if constexpr (_Type == http_type_enum::post) {
				return request_.post(url, data, headers);
			}
			else {
				return request_.get(url, headers);
			}
		}
	private:
		template<typename _Ret>
		_Ret response(std::string const&json) {
			_Ret result;
			v3::json_convert::deserialize(json, result);
			return result;
		}
	private:
		http_request request_;
	};
}

/**
 * @brief http_network 类用于管理 HTTP 网络请求，包括获取和设置设备 ID、发送售后请求、获取通用配置信息等功能，并实现了单例模式。
 */
class http_network {
public:
	/**
	 * @brief 返回 http_network 的单例实例指针。
	 * @return 指向 http_network 单例对象的指针。
	 */
	static http_network* instance() {
		static http_network g_http_network;
		return &g_http_network;
	}
	/**
	 * @brief 析构 http_network 对象，释放相关资源。
	 */
	~http_network() {
	}
	/**
	 * @brief 设置设备ID。
	 * @param device_id 要设置的设备ID字符串。
	 */
	void set_device_id(std::string const& device_id) {
		device_id_ = device_id;
	}
	/**
	 * @brief 发送请求以获取报警配置信息。
	 * @return 返回包含报警配置信息的 web_response_info<web_alarm_config_info> 对象。
	 */
	web_response_info<web_alarm_config_info> alarm_request() {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 1; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/alarm_type";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::get, web_response_info<web_alarm_config_info>>(config->value);
	}
	/**
	 * @brief 发送请求以获取品牌配置信息。
	 * @return 返回包含品牌配置信息的 web_response_info<web_brand_config_info> 对象。
	 */
	web_response_info<web_brand_config_info> brand_request() {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 2; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/brand_type";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::get, web_response_info<web_brand_config_info>>(config->value);
	}
	/**
	 * @brief 请求设备配置信息并返回响应结果。
	 * @return 包含设备配置信息的 web_response_info<web_device_config_info> 对象。
	 */
	web_response_info<web_device_config_info> device_request() {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 3; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/device_type";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::get, web_response_info<web_device_config_info>>(config->value);
	}
	/**
	 * @brief 发起一次配置信息的网络请求，并返回响应结果。
	 * @return 包含配置信息的 web_response_info<web_fitting_config_info> 对象。
	 */
	web_response_info<web_fitting_config_info> fitting_request() {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 4; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/fitting_type";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::get, web_response_info<web_fitting_config_info>>(config->value);
	}
	/**
	 * @brief 根据给定的 key 获取通用配置信息的 Web 响应。
	 * @param key 用于查询配置信息的键值。
	 * @return 包含通用配置信息的 web_response_info<web_general_config_info> 对象。
	 */
	web_response_info<web_general_config_info> general_request(int key) {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 5; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/config";
		}
		std::string url = config->value + "?key=" + std::to_string(key);
		LOG_INFO << "Url:" << url;
		return request<utils::http_type_enum::get, web_response_info<web_general_config_info>>(url);
	}
	/**
	 * @brief 请求模型配置信息并返回响应结果。
	 * @return 包含模型配置信息的 web_response_info<web_spec_config_info> 对象。
	 */
	web_response_info<web_spec_config_info> spec_request() {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 6; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/spec_type";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::get, web_response_info<web_spec_config_info>>(config->value);
	}
	/**
	 * @brief 未提供函数定义，无法生成文档。请提供有效的函数代码。
	 */
	web_response_info<web_level_config_info> level_request() {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 7; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/base/level_type";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::get, web_response_info<web_level_config_info>>(config->value);
	}
	/**
	 * @brief 同步请求报警信息并返回结果。
	 * @param value 包含同步报警信息的常量引用。
	 * @return 返回包含请求结果的 web_message_info 对象。
	 */
	web_message_info update_alarm_request(web_sync_alarm_info const&value) {
		auto config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 8; }).first();
		if (!config) {
			config.reset(new web_general_config_info());
			config->value = "http://127.0.0.1:9004/api/upload/alarm";
		}
		LOG_INFO << "Url:" << config->value;
		return request<utils::http_type_enum::post, web_message_info>(config->value);
	}
private:
	/**
	 * @brief 初始化或处理 HTTP 网络操作。
	 */
	http_network():
		app_name_("work_order_service") { }
private:
	/**
	 * @brief 发送带有指定数据的 HTTP 请求，并返回响应结果。
	 * @tparam _Ret 请求返回值的类型。
	 * @tparam _Value 要序列化并发送的数据类型。
	 * @tparam _Type HTTP 请求类型（如 GET、POST 等），由 utils::http_type_enum 枚举指定。
	 * @param url 要请求的目标 URL。
	 * @param data 要随请求发送的数据，将被序列化为 JSON 格式。
	 * @return HTTP 请求的响应结果，类型为 _Ret。
	 */
	template<utils::http_type_enum _Type, typename _Ret,typename _Value>
	_Ret request(std::string const& url, _Value const& data) {
		return http_.request<_Type, _Ret>(http::url_encode(url), v3::json_convert::serialize(data), { {"Content-Type","application/json"},{"User-Agent","Chrome"},{"Token",sign()},{"DeviceId",device_id_ },{"AppName",app_name_ } });
	}
	/**
	 * @brief 发送一个HTTP POST请求，并返回指定类型的结果。
	 * @tparam _Ret 请求返回值的类型。
	 * @tparam _Type HTTP请求类型的枚举值（通常为utils::http_type_enum类型）。
	 * @param url 要请求的URL地址。
	 * @param data 要发送的请求数据（通常为JSON格式）。
	 * @return 指定类型的HTTP响应结果。
	 */
	template<utils::http_type_enum _Type, typename _Ret>
	_Ret request(std::string const&url,std::string const&data) {
		return http_.request<_Type, _Ret>(http::url_encode(url), data, { {"Content-Type","application/json"},{"User-Agent","Chrome"},{"Token",sign()},{"DeviceId",device_id_ },{"AppName",app_name_ } });
	}
	/**
	 * @brief 发送一个HTTP GET请求到指定的URL，并返回指定类型的结果。
	 * @tparam _Ret 请求返回值的类型。
	 * @tparam _Type HTTP请求类型的枚举值，通常为utils::http_type_enum类型（此函数内部固定为GET）。
	 * @param url 要请求的目标URL字符串。
	 * @return 指定类型（_Ret）的HTTP响应结果。
	 */
	template<utils::http_type_enum _Type, typename _Ret>
	_Ret request(std::string const& url) {
		return http_.request<_Type, _Ret>(http::url_encode(url), { {"Content-Type","text/html"},{"User-Agent","Chrome"},{"Token",sign()},{"DeviceId",device_id_ },{"AppName",app_name_ } });
	}
	/**
	 * @brief 生成设备标识符的签名字符串。
	 * @return 返回通过将 device_id_ 与固定字符串拼接后计算得到的 MD5 签名字符串。
	 */
	std::string sign() {
		return v3::utils::md5(device_id_ + "GqBRMZHKlBDCWlwyYolk24BXHElKUo5Z");
	}
private:
	/**
	 * @brief utils::web_http 类型的 http_ 变量。
	 */
	utils::web_http http_;
	/**
	 * @brief 设备的唯一标识符字符串。
	 */
	std::string device_id_;
	/**
	 * @brief 应用程序的名称。
	 */
	std::string app_name_;
};