#include "JWTDecoder.h"
#include "json/json.hpp"
#include <ctime>
#include <vector>
#include <cstdio>

using json = nlohmann::json;

// ─── Base64Url Decode ─────────────────────────────────

static const std::string BASE64_CHARS =
    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

static std::vector<unsigned char> Base64Decode(const std::string& input)
{
    std::string s = input;
    // Convert URL-safe to standard Base64
    for (char& c : s) {
        if (c == '-') c = '+';
        if (c == '_') c = '/';
    }
    // Pad
    while (s.size() % 4 != 0)
        s += '=';

    std::vector<unsigned char> result;
    int i = 0;
    int val = 0;
    int valb = -8;
    for (char c : s) {
        if (c == '=') break;
        size_t pos = BASE64_CHARS.find(c);
        if (pos == std::string::npos) continue;
        val = (val << 6) + static_cast<int>(pos);
        valb += 6;
        if (valb >= 0) {
            result.push_back(static_cast<unsigned char>((val >> valb) & 0xFF));
            valb -= 8;
        }
    }
    return result;
}

std::string JWTDecoder::Base64UrlDecode(const std::string& input)
{
    auto bytes = Base64Decode(input);
    return std::string(bytes.begin(), bytes.end());
}

// ─── Parse Payload ────────────────────────────────────

JWTDecoder::Payload JWTDecoder::ParsePayload(const std::string& jsonStr)
{
    Payload p;
    try {
        auto j = json::parse(jsonStr);
        if (j.contains("sub"))  p.sub = j["sub"].get<int64_t>();
        if (j.contains("username")) p.username = j["username"].get<std::string>();
        if (j.contains("role"))     p.role = j["role"].get<std::string>();
        if (j.contains("device_id")) p.device_id = j["device_id"].get<int64_t>();
        if (j.contains("iat"))  p.iat = j["iat"].get<int64_t>();
        if (j.contains("exp"))  p.exp = j["exp"].get<int64_t>();
        p.valid = true;
    } catch (const std::exception& e) {
        printf("[JWTDecoder] parse error: %s\n", e.what());
        p.valid = false;
    }
    return p;
}

// ─── Public API ───────────────────────────────────────

JWTDecoder::Payload JWTDecoder::Decode(const std::string& token)
{
    Payload p;

    // Split header.payload.signature
    size_t dot1 = token.find('.');
    if (dot1 == std::string::npos) return p;
    size_t dot2 = token.find('.', dot1 + 1);
    if (dot2 == std::string::npos) return p;

    std::string payloadEncoded = token.substr(dot1 + 1, dot2 - dot1 - 1);
    std::string payloadJson = Base64UrlDecode(payloadEncoded);

    return ParsePayload(payloadJson);
}

bool JWTDecoder::IsExpired(int64_t expUnix)
{
    return static_cast<int64_t>(std::time(nullptr)) > expUnix;
}
