#ifndef RTX_API_CLIENT_H
#define RTX_API_CLIENT_H

#include <string>
#include <memory>
#include "JsonSerializer.h"

namespace rtx
{
    template <typename T>
    struct GatewayResp : public Serializable
    {
        std::string id;
        int code;
        std::string message;
        std::shared_ptr<Serializable> data;

        Json::Value toJson() const
        {
            Json::Value root;
            SERIALIZE_JSON_FIELD(root, id);
            SERIALIZE_JSON_FIELD(root, code);
            SERIALIZE_JSON_FIELD(root, message);
            SERIALIZE_JSON_PTR_FIELD(root, data);
            return root;
        }

        void fromJson(const Json::Value &json)
        {
            // 编译时检查 T 是否是 Serializable 或其派生类
            static_assert(std::is_base_of<Serializable, T>::value, "T must be a subclass of Serializable");

            DESERIALIZE_JSON_FIELD(json, id);
            DESERIALIZE_JSON_FIELD(json, code);
            DESERIALIZE_JSON_FIELD(json, message);
            data = std::make_shared<T>();
            DESERIALIZE_JSON_PTR_FIELD(json, data);
        }

        std::shared_ptr<T> getData() 
        {
            return std::dynamic_pointer_cast<T>(data);
        } 
    };

    namespace common
    {
        class InnelReq : public Serializable
        {
        public:
            InnelReq();
            InnelReq(const std::string &clientUniqueKey, const std::string &iotToken, std::string language = "zh_CN", std::string apiVer = "1.0.0");

            Json::Value toJson() const override;
            void fromJson(const Json::Value &json) override;

        private:
            std::string apiVer;
            std::string iotToken;
            std::string language;
            std::string clientUniqueKey;
        };
        REGISTER_SERIALIZE_OBJECT(InnelReq);

        class RtxApiReq : public Serializable
        {
        public:
            RtxApiReq(std::shared_ptr<Serializable> params);
            RtxApiReq(const std::string &clientUniqueKey, const std::string &iotToken, std::shared_ptr<Serializable> params);

            Json::Value toJson() const override;
            void fromJson(const Json::Value &json) override;

        private:
            std::string id;
            std::string version;
            InnelReq request;
            std::shared_ptr<Serializable> params;
        };
        REGISTER_SERIALIZE_OBJECT(RtxApiReq);

        struct RtxApiResp : public Serializable
        {
            RtxApiResp(int32_t curlCode, const Json::Value &data) : curlCode(curlCode), data(data) {}
            int32_t curlCode;
            Json::Value data;

            Json::Value toJson() const override;
            void fromJson(const Json::Value &json) override;
        };
        REGISTER_SERIALIZE_OBJECT(RtxApiResp);

        class RtxApiClient
        {
        private:
            std::string appKey;
            std::string appSecret;

        private:
            RtxApiClient(const std::string &appKey, const std::string &appSecret)
                : appKey(appKey), appSecret(appSecret) {}

        public:
            static RtxApiClient getInstance(const std::string &appKey, const std::string &appSecret)
            {
                return RtxApiClient(appKey, appSecret);
            }

            /**
             * function: post http request with json string
             * return: if success RtxApiResp.curlCode is 0, else return nullptr or RtxApiResp.curlCode not 0
             */
            std::shared_ptr<RtxApiResp> postWithBody(const std::string &host, const std::string &path, const std::string &bodyStr);
        };
    }
}

#endif