#include <stdint.h>

#include <string>

#include "absl/strings/escaping.h"
#include "openssl/hpke.h"
#include "quiche/common/platform/api/quiche_test.h"
#include "quiche/oblivious_http/buffers/oblivious_http_response.h"

namespace quiche {
namespace {

struct ObliviousHttpResponseTestStrings {
  std::string test_case_name;
  uint8_t key_id;
  std::string request_plaintext;
  std::string response_plaintext;
};

std::string GetHpkePrivateKey() {
  absl::string_view hpke_key_hex =
      "b77431ecfa8f4cfc30d6e467aafa06944dffe28cb9dd1409e33a3045f5adc8a1";
  return absl::HexStringToBytes(hpke_key_hex);
}

std::string GetHpkePublicKey() {
  absl::string_view public_key =
      "6d21cfe09fbea5122f9ebc2eb2a69fcc4f06408cd54aac934f012e76fcdcef62";
  return absl::HexStringToBytes(public_key);
}

const ObliviousHttpHeaderKeyConfig GetOhttpKeyConfig(uint8_t key_id,
                                                     uint16_t kem_id,
                                                     uint16_t kdf_id,
                                                     uint16_t aead_id) {
  auto ohttp_key_config =
      ObliviousHttpHeaderKeyConfig::Create(key_id, kem_id, kdf_id, aead_id);
  EXPECT_TRUE(ohttp_key_config.ok());
  return std::move(ohttp_key_config.value());
}

bssl::UniquePtr<EVP_HPKE_KEY> ConstructHpkeKey(
    absl::string_view hpke_key,
    const ObliviousHttpHeaderKeyConfig &ohttp_key_config) {
  bssl::UniquePtr<EVP_HPKE_KEY> bssl_hpke_key(EVP_HPKE_KEY_new());
  EXPECT_NE(bssl_hpke_key, nullptr);
  EXPECT_TRUE(EVP_HPKE_KEY_init(
      bssl_hpke_key.get(), ohttp_key_config.GetHpkeKem(),
      reinterpret_cast<const uint8_t *>(hpke_key.data()), hpke_key.size()));
  return bssl_hpke_key;
}
}  // namespace

absl::StatusOr<ObliviousHttpRequest>
CreateClientObliviousRequestWithSeedForTesting(
    absl::string_view plaintext_payload, absl::string_view hpke_public_key,
    const ObliviousHttpHeaderKeyConfig &ohttp_key_config,
    absl::string_view seed) {
  return ObliviousHttpRequest::EncapsulateWithSeed(
      plaintext_payload, hpke_public_key, ohttp_key_config, seed);
}

using ObliviousHttpParameterizedTest =
    test::QuicheTestWithParam<ObliviousHttpResponseTestStrings>;

TEST_P(ObliviousHttpParameterizedTest, TestEndToEndWithOfflineStrings) {
  // For each test case, verify end to end request-handling and
  // response-handling.
  const ObliviousHttpResponseTestStrings &test = GetParam();

  auto ohttp_key_config =
      GetOhttpKeyConfig(test.key_id, EVP_HPKE_DHKEM_X25519_HKDF_SHA256,
                        EVP_HPKE_HKDF_SHA256, EVP_HPKE_AES_256_GCM);
  // Round-trip request flow.
  auto client_req_encap = ObliviousHttpRequest::CreateClientObliviousRequest(
      test.request_plaintext, GetHpkePublicKey(), ohttp_key_config);
  EXPECT_TRUE(client_req_encap.ok());
  ASSERT_FALSE(client_req_encap->EncapsulateAndSerialize().empty());
  auto server_req_decap = ObliviousHttpRequest::CreateServerObliviousRequest(
      client_req_encap->EncapsulateAndSerialize(),
      *(ConstructHpkeKey(GetHpkePrivateKey(), ohttp_key_config)),
      ohttp_key_config);
  EXPECT_TRUE(server_req_decap.ok());
  EXPECT_EQ(server_req_decap->GetPlaintextData(), test.request_plaintext);

  // Round-trip response flow.
  auto server_resp_encap = ObliviousHttpResponse::CreateServerObliviousResponse(
      test.response_plaintext,
      *(server_req_decap->oblivious_http_request_context()));
  EXPECT_TRUE(server_resp_encap.ok());
  ASSERT_FALSE(server_resp_encap->EncapsulateAndSerialize().empty());
  auto client_resp_decap = ObliviousHttpResponse::CreateClientObliviousResponse(
      server_resp_encap->EncapsulateAndSerialize(),
      *(client_req_encap->oblivious_http_request_context()));
  EXPECT_TRUE(client_resp_decap.ok());
  EXPECT_EQ(client_resp_decap->GetPlaintextData(), test.response_plaintext);
}

INSTANTIATE_TEST_SUITE_P(
    ObliviousHttpParameterizedTests, ObliviousHttpParameterizedTest,
    testing::ValuesIn<ObliviousHttpResponseTestStrings>(
        {{"test_case_1", 4, "test request 1", "test response 1"},
         {"test_case_2", 6, "test request 2", "test response 2"},
         {"test_case_3", 7, "test request 3", "test response 3"},
         {"test_case_4", 2, "test request 4", "test response 4"},
         {"test_case_5", 1, "test request 5", "test response 5"},
         {"test_case_6", 7, "test request 6", "test response 6"},
         {"test_case_7", 3, "test request 7", "test response 7"},
         {"test_case_8", 9, "test request 8", "test response 8"},
         {"test_case_9", 3, "test request 9", "test response 9"},
         {"test_case_10", 4, "test request 10", "test response 10"}}),
    [](const testing::TestParamInfo<ObliviousHttpParameterizedTest::ParamType>
           &info) { return info.param.test_case_name; });

}  // namespace quiche
