#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_after_response_info.h"

using namespace robotics;
/**
 * @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_after_response_info> 对象。
	 */
	web_response_info<web_after_response_info> request_after() {
		auto url_config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 3; }).first();
		if (!url_config) {
			url_config.reset(new web_general_config_info());
			url_config->value = "http://127.0.0.1:8002/api/after/get_after";
		}
		std::string url = url_config->value + "?devece_id=" + device_id_;
		LOG_INFO << "Url:" << url;
		return get<web_after_response_info>(http::url_encode(url));
	}
	/**
	 * @brief 根据给定的 key 获取通用配置信息的 Web 响应。
	 * @param key 用于查询配置信息的键值。
	 * @return 包含通用配置信息的 web_response_info<web_general_config_info> 对象。
	 */
	web_response_info<web_general_config_info> request_general(int key) {
		auto url_config = xml_context::from<web_general_config_info>().where([](auto it) {return it->enable && it->key == 4; }).first();
		if (!url_config) {
			url_config.reset(new web_general_config_info());
			url_config->value = "http://127.0.0.1:8002/api/base/config";
		}
		std::string url = url_config->value + "?devece_id=" + device_id_ + "&app_name=after_service&key=" + std::to_string(key);
		LOG_INFO << "Url:" << url;
		return get<web_general_config_info>(http::url_encode(url));
	}
private:
	/**
	 * @brief 初始化或处理 HTTP 网络操作。
	 */
	http_network() {}
	template<typename _Ret>
	web_response_info<_Ret> post(std::string const& url, std::string const& data) {
		http::web_request request = http::make_request(url);
		request.method(http::verb::post);
		request.set(http::field::user_agent, "Chrome");
		request.set(http::field::content_type, "application/json");
		request.set("token", sign());
		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()));
		}
		std::string json = response.body();
		web_response_info<_Ret> result;
		LOG_INFO << json;
		v3::json_convert::deserialize(json, result);
		return result;
	}
	/**
	 * @brief 发送一个 HTTP GET 请求到指定的 URL，并返回响应体内容。
	 * @param url 要请求的目标 URL。
	 * @return HTTP 响应的正文内容（body），类型为 std::string。如果请求失败，则抛出 std::runtime_error 异常。
	 */
	template<typename _Ret>
	web_response_info<_Ret> get(std::string const& url) {
		http::web_request request = http::make_request(url);
		request.method(http::verb::get);
		request.set(http::field::user_agent, "Chrome");
		request.set(http::field::content_type, "text/html");
		request.set("token", sign());
		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()));
		}
		std::string json = response.body();
		web_response_info<_Ret> result;
		LOG_INFO << json;
		v3::json_convert::deserialize(json, result);
		return result;
	}
private:
	/**
	 * @brief 生成设备标识符的签名字符串。
	 * @return 返回通过将 device_id_ 与固定字符串拼接后计算得到的 MD5 签名字符串。
	 */
	std::string sign() {
		return v3::utils::md5(device_id_ + "GqBRMZHKlBDCWlwyYolk24BXHElKUo5Z");
	}
private:
	/**
	 * @brief 设备的唯一标识符字符串。
	 */
	std::string device_id_;
};