// LicenseX C++ SDK
// Copy this file and licensex.cpp into your project. Requires C++17 and
// links against winhttp.lib and bcrypt.lib (Windows only).
//
// Every response from the server (except InvalidCredentials, which the
// server can't sign — see below) carries an HMAC-SHA256 signature computed
// with your app's api_secret. This SDK verifies that signature before
// trusting anything in the response body, so a patched/cracked client
// would need to recover api_secret itself, not just flip a boolean.
#pragma once

#include <string>
#include <optional>

namespace licensex {

enum class ErrorCode {
    None,
    InvalidCredentials,  // app_id/api_secret rejected. Sent UNSIGNED — the
                          // server has no proof you're who you claim to be,
                          // so there's nothing to sign the response with.
    ServerRejected,       // Verified success:false — key is genuinely
                          // invalid/expired/banned/revoked, or (for
                          // ResetHwid) the reset limit was hit.
    SignatureInvalid,     // Response body's HMAC didn't match. Tampered in
                          // transit, or api_secret doesn't match the
                          // dashboard. NEVER trust auth.ok when this fires.
    ResetLimitReached,    // ResetHwid() specific: resetsUsed/resetsAllowed
                          // on the result say exactly where you stand.
    NotFound,             // GetVariable() specific: no variable with that
                          // name exists for this app.
    RateLimited,          // Too many requests — back off and retry.
    NetworkError,         // Request never got a response.
    Timeout,              // Server didn't respond in time.
    ParseError,           // Response body wasn't valid JSON.
};

struct LicenseInfo {
    std::string status;                       // "active" | "expired" | "banned" | "unused"
    std::optional<std::string> expiresAt;      // nullopt = lifetime license
};

struct AuthResult {
    bool ok = false;
    ErrorCode error = ErrorCode::None;
    std::string errorMessage;
    LicenseInfo license;
};

struct ResetResult {
    bool ok = false;
    ErrorCode error = ErrorCode::None;
    std::string errorMessage;
    int resetsUsed = 0;
    int resetsAllowed = 0;
};

struct VariableResult {
    bool ok = false;
    ErrorCode error = ErrorCode::None;
    std::string errorMessage;
    std::string value;
};

struct LogResult {
    bool ok = false;
    ErrorCode error = ErrorCode::None;
    std::string errorMessage;
};

// Derives a stable per-machine fingerprint from the CPU vendor/model
// string (CPUID), MachineGuid (HKLM\SOFTWARE\Microsoft\Cryptography), and
// the system drive's volume serial number, concatenated and SHA-256'd.
// Survives reboots and most driver/OS updates; changes on a clean
// reformat, which is the intended trigger for a HWID reset.
std::string GetHardwareId();

class Client {
public:
    // baseUrl: your LicenseX deployment, no trailing slash
    //   (e.g. "https://your-licensex-deployment.example.com")
    // appId / apiSecret: from Dashboard → your application → API keys.
    //   Never hardcode apiSecret in a debug build or log it — anyone who
    //   extracts it can forge signed responses for that app.
    Client(std::string baseUrl, std::string appId, std::string apiSecret);

    // POST /api/v1/authenticate — validates a license key + HWID.
    AuthResult Authenticate(const std::string& licenseKey, const std::string& hwid);

    // POST /api/v1/reset-hwid — clears every device slot on a license,
    // bounded by the app's max_hwid_resets. Call this when Authenticate()
    // returns ServerRejected with "Device limit reached" and you've
    // confirmed with the user it's really a new/reformatted machine.
    ResetResult ResetHwid(const std::string& licenseKey);

    // POST /api/v1/variable — fetches a dashboard-configured value
    // (feature flag, min version, download URL, ...) by name.
    VariableResult GetVariable(const std::string& name);

    // POST /api/v1/log — records a lightweight event. licenseKey is
    // optional (omit for pre-auth events like "loader started").
    LogResult Log(const std::string& message, const std::string& licenseKey = "");

private:
    std::string baseUrl_;
    std::string appId_;
    std::string apiSecret_;
};

}  // namespace licensex
