// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest

#include <everest/helpers/helpers.hpp>
#include <everest/tls/openssl_util.hpp>

#include <unordered_map>

#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>
#include <fmt/format.h>

#include <generated/types/authorization.hpp>

namespace everest::helpers {
std::string redact(const std::string& token) {
    auto hash = std::hash<std::string>{}(token);
    return fmt::format("[redacted] hash: {:X}", hash);
}

types::authorization::ProvidedIdToken redact(const types::authorization::ProvidedIdToken& token) {
    types::authorization::ProvidedIdToken redacted_token = token;
    redacted_token.id_token.value = redact(redacted_token.id_token.value);
    if (redacted_token.parent_id_token.has_value()) {
        auto& parent_id_token = redacted_token.parent_id_token.value();
        parent_id_token.value = redact(parent_id_token.value);
    }
    return redacted_token;
}

std::string escape_html(const std::string& html) {
    std::string escaped_html;
    escaped_html.reserve(html.size());
    for (const auto& character : html) {
        switch (character) {
        case '\"':
            escaped_html.append("&quot;");
            break;
        case '\'':
            escaped_html.append("&apos;");
            break;
        case '&':
            escaped_html.append("&amp;");
            break;
        case '<':
            escaped_html.append("&lt;");
            break;
        case '>':
            escaped_html.append("&gt;");
            break;
        default:
            escaped_html.push_back(character);
            break;
        }
    }
    return escaped_html;
}

bool is_equal_case_insensitive(const std::string& str1, const std::string& str2) {
    if (str1.length() != str2.length()) {
        return false;
    }
    return std::equal(str1.begin(), str1.end(), str2.begin(),
                      [](char a, char b) { return std::tolower(a) == std::tolower(b); });
}

bool is_equal_case_insensitive(const types::authorization::IdToken& token1,
                               const types::authorization::IdToken& token2) {
    return is_equal_case_insensitive(token1.value, token2.value) && token1.type == token2.type;
}

bool is_equal_case_insensitive(const types::authorization::ProvidedIdToken& token1,
                               const types::authorization::ProvidedIdToken& token2) {
    return is_equal_case_insensitive(token1.id_token.value, token2.id_token.value) &&
           token1.id_token.type == token2.id_token.type;
}

namespace {
boost::uuids::random_generator& get_rng() {
    static thread_local boost::uuids::random_generator rng;
    return rng;
}
} // namespace

std::string get_uuid() {
    return boost::uuids::to_string(get_rng()()); // 36 characters
}

std::string get_base64_uuid() {
    boost::uuids::uuid uuid = get_rng()();
    std::string encoded = openssl::base64_encode(uuid.data, uuid.size(), false);
    encoded.erase(std::remove(encoded.begin(), encoded.end(), '='), encoded.end()); // remove padding
    return encoded;                                                                 // 22 characters
}

std::string get_base64_id() {
    std::array<std::uint8_t, 12> random_bytes;
    boost::uuids::uuid uuid = get_rng()();
    std::memcpy(random_bytes.data(), uuid.data, random_bytes.size());
    std::string encoded = openssl::base64_encode(random_bytes.data(), random_bytes.size(), false);
    return encoded; // 16 characters
}

} // namespace everest::helpers
