/**
  ******************************************************************************
  * @file           : Api.hpp
  * @author         : Dream
  * @brief          : API class for handling authentication and data requests
  * @attention      : None
  * @date           : 24-10-3
  ******************************************************************************
  */

#ifndef API_HPP
#define API_HPP

#include <json.hpp>
#include <map>
#include <string>
#include <string_view>
#include "obfuscate.hpp"

struct LoginResponse
{
    int code = -1; // 登录状态码
    struct Msg
    {
        time_t id = -1; // 卡密ID
        std::string kmtype; // 卡密时长类型
        std::string token; // 登录令牌
        std::string ktype; // 卡密类型
        time_t vip = 0; // 到期时间戳
        std::string check; // 数据校验
        std::string dateTime; // 服务器时间
        std::string expireDateTime; // 到期时间
    } msg;

    time_t time = 0; // 服务器时间戳
    bool login = false;
};

struct CustomResponse
{
    std::string token; // 登录令牌
    int code = -1; // 状态码
    struct Msg
    {
        time_t endtime = 0; // 到期时间戳
        std::string type; // 卡密类型
        std::string timetype; // 卡密时长类型
        std::string check; // 数据校验
    } msg;

    time_t time = 0; // 当前时间戳
    std::string timeStr; // 格式化剩余时间
};

struct AnnouncementResponse
{
    int code = -1; // 公告状态码
    struct Msg
    {
        std::string app_gg; // 公告内容
    } msg;

    time_t time = 0; // 服务器时间戳
    std::string dateTime; // 格式化时间
};

struct UpdateInfo
{
    int code = -1; // 状态码
    std::string msg; // 消息
    std::string version; // 版本号
    std::string updateshow; // 更新显示内容
    std::string updateurl; // 更新URL
    std::string updatemust; // 是否强制更新
    time_t time = 0; // 服务器时间戳
};

inline const std::map<std::string, std::string> kmtypeDescription = {
    {std::string(AY_OBFUSCATE("free")), std::string(AY_OBFUSCATE("免费模式"))},
    {std::string(AY_OBFUSCATE("hour")), std::string(AY_OBFUSCATE("小时卡"))},
    {std::string(AY_OBFUSCATE("day")), std::string(AY_OBFUSCATE("日卡"))},
    {std::string(AY_OBFUSCATE("week")), std::string(AY_OBFUSCATE("周卡"))},
    {std::string(AY_OBFUSCATE("month")), std::string(AY_OBFUSCATE("月卡"))},
    {std::string(AY_OBFUSCATE("season")), std::string(AY_OBFUSCATE("高级VIP"))},      // TODO 季节
    {std::string(AY_OBFUSCATE("year")), std::string(AY_OBFUSCATE("高级SVIP"))},       // TODO 年卡
    {std::string(AY_OBFUSCATE("longuse")), std::string(AY_OBFUSCATE("至尊SVIP"))},    // TODO 长期
    {std::string(AY_OBFUSCATE("single")), std::string(AY_OBFUSCATE("点卡"))}
};

inline const std::map<int, std::string> loginStatusDescription = {
    {732, std::string(AY_OBFUSCATE("登录成功"))},
    {201, std::string(AY_OBFUSCATE("未知报错请联系客服"))},
    {100, std::string(AY_OBFUSCATE("未绑定应用ID"))},
    {101, std::string(AY_OBFUSCATE("应用不存在"))},
    {102, std::string(AY_OBFUSCATE("应用已关闭"))},
    {103, std::string(AY_OBFUSCATE("已关闭登录"))},
    {104, std::string(AY_OBFUSCATE("签名为空"))},
    {105, std::string(AY_OBFUSCATE("数据过期"))},
    {106, std::string(AY_OBFUSCATE("签名有误"))},
    {107, std::string(AY_OBFUSCATE("数据为空"))},
    {108, std::string(AY_OBFUSCATE("未提交时间戳"))},
    {112, std::string(AY_OBFUSCATE("未提交设备码"))},
    {148, std::string(AY_OBFUSCATE("卡密为空"))},
    {149, std::string(AY_OBFUSCATE("卡密不存在"))},
    {150, std::string(AY_OBFUSCATE("卡密已使用"))},
    {151, std::string(AY_OBFUSCATE("卡密已被禁用"))},
    {152, std::string(AY_OBFUSCATE("卡密类型不一致"))}
};

class API
{
public:
    API(std::string kami, std::string device_key);

    [[nodiscard]] bool single_code_login(LoginResponse& ret) const;
    static void parseAnnouncementResponse(AnnouncementResponse& response);
    [[nodiscard]] UpdateInfo parseUpdateResponse() const;
    void parseCustomResponse(CustomResponse& ret) const;
    [[nodiscard]] uint64_t get_remote_variable(std::string_view variable_name, std::string_view token) const;
    [[nodiscard]] nlohmann::json single_code_unbind() const;

private:
    std::string kami;
    std::string device_key;

    [[nodiscard]] std::string generate_sign(time_t tt, std::string_view extra = "") const;
    [[nodiscard]] static nlohmann::json send_encrypted_request(std::string_view data_to_encrypt, const std::string& key);
    [[nodiscard]] static LoginResponse parseLoginResponse(const nlohmann::json& root);
    [[nodiscard]] static std::string convertTimestampToDateTime(time_t timestamp);
    [[nodiscard]] nlohmann::json get_updates() const;
    [[nodiscard]] static nlohmann::json get_announcement();
    inline static const std::string appkey = std::string(AY_OBFUSCATE("Zpmr6I7JP6yM5R0I"));
    inline static const std::string login_id = std::string(AY_OBFUSCATE("778FF5312FC"));
    inline static const std::string unbind_id = std::string(AY_OBFUSCATE("F16EC9E49D9"));
    inline static const std::string announcement_id = std::string(AY_OBFUSCATE("B1C1837EE43"));
    inline static const std::string update_id = std::string(AY_OBFUSCATE("AB6FA9E9E52"));
    inline static const std::string remote_variable_id = std::string(AY_OBFUSCATE("19C09E8F9B1"));
    inline static const std::string heartbeat_id = std::string(AY_OBFUSCATE("835A8437B2C"));

    inline static constexpr int Local_heck_code = 98458;
    inline static constexpr int remote_variable_code = 7816;
    inline static constexpr int heartbeat_code = 53522;
    inline static constexpr int announcement_code = 11355;
    inline static constexpr int update_code = 99442;
};

void convertSecondsToTime(time_t seconds, std::string& timeStr);
time_t calculateRemainingTime(const CustomResponse& response);

#endif // API_HPP
