#include "auth.h"

#include <crypto/sha.h>
#include <random.h>

#include <algorithm>

namespace paritypp {

// --- auth_store ---

void auth_store::add_client(const std::string& name, const std::vector<uint8_t>& key) {
    std::lock_guard<std::mutex> lock(mutex_);
    clients_[name] = key;
}

void auth_store::add_client(const std::string& name, const std::string& key_str) {
    std::vector<uint8_t> key(key_str.begin(), key_str.end());
    add_client(name, key);
}

bool auth_store::remove_client(const std::string& name) {
    std::lock_guard<std::mutex> lock(mutex_);
    return clients_.erase(name) > 0;
}

bool auth_store::lookup(const std::string& name, std::vector<uint8_t>& key_out) const {
    std::lock_guard<std::mutex> lock(mutex_);
    auto it = clients_.find(name);
    if (it == clients_.end()) return false;
    key_out = it->second;
    return true;
}

bool auth_store::has_client(const std::string& name) const {
    std::lock_guard<std::mutex> lock(mutex_);
    return clients_.count(name) > 0;
}

std::vector<std::string> auth_store::list_clients() const {
    std::lock_guard<std::mutex> lock(mutex_);
    std::vector<std::string> result;
    result.reserve(clients_.size());
    for (const auto& kv : clients_) {
        result.push_back(kv.first);
    }
    return result;
}

// --- auth helpers ---

std::vector<uint8_t> auth::generate_nonce(size_t len) {
    std::vector<uint8_t> nonce(len);
    netplus::fillRandomBytes(nonce.data(), len);
    return nonce;
}

std::vector<uint8_t> auth::compute_hmac(const std::vector<uint8_t>& key,
                                         const std::vector<uint8_t>& data) {
    return netplus::hmac_sha256(key, data);
}

bool auth::verify_hmac(const std::vector<uint8_t>& key,
                       const std::vector<uint8_t>& data,
                       const std::vector<uint8_t>& expected_hmac) {
    auto computed = netplus::hmac_sha256(key, data);
    if (computed.size() != expected_hmac.size()) return false;
    // Constant-time comparison to prevent timing attacks
    uint8_t diff = 0;
    for (size_t i = 0; i < computed.size(); i++) {
        diff |= computed[i] ^ expected_hmac[i];
    }
    return diff == 0;
}

} // namespace paritypp
