// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "crypto/default/cms/cms_test_helper.h"

#include <cstddef>
#include <cstdint>
#include <memory>
#include <string>

#include "absl/log/absl_check.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "crypto/default/cms/cms_parser.h"
#include "openssl/base.h"
#include "openssl/bio.h"
#include "openssl/bytestring.h"
#include "openssl/obj.h"
#include "openssl/pem.h"
#include "openssl/x509.h"
#include "testing/test_file_utils.h"

namespace credentio_cms {

constexpr absl::string_view kTestRepoDir = "credentio/";

std::string GetRawFileContents(const std::string& filename) {
  std::string path =
      absl::StrCat(kTestRepoDir, "crypto/default/cms/testdata/", filename);
  auto contents = credentio_testing::GetContents(path);
  ABSL_CHECK(contents.ok())
      << "Failed to load: " << path << ", " << contents.status();
  return *contents;
}

std::string GetFileContents(const std::string& filename) {
  std::string contents = GetRawFileContents(filename);
  // Normalize line endings by replacing \n with \r\n when needed.
  std::string normalized_contents;
  bool has_cr = false;
  for (char c : contents) {
    if (c == '\r') {
      has_cr = true;
    } else {
      if (c == '\n' && !has_cr) {
        normalized_contents += '\r';
      }
      has_cr = false;
    }
    normalized_contents += c;
  }
  return normalized_contents;
}

// Quick and dirty functions to extract the CMS object. It probably only works
// on the test cases.
std::string GetCms(const std::string& message) {
  auto pos = message.find("name=\"smime.p7s\"");
  if (pos == std::string::npos) {
    pos = message.find("name=\"smime.p7m\"");
  }
  if (pos == std::string::npos) {
    pos = message.find("name=smime.p7s");
  }
  if (pos == std::string::npos) {
    pos = message.find("name=smime.p7m");
  }
  if (pos == std::string::npos) {
    pos = message.find("name=smime.p7c");
  }
  ABSL_CHECK(pos != std::string::npos);
  auto start = message.find("\x0d\x0a\x0d\x0a", pos);
  ABSL_CHECK(start != std::string::npos);
  start += 2;
  auto end = message.find('-', start);
  if (end == std::string::npos) {
    end = message.find("\x0d\x0a\x0d\x0a", start);
  }
  if (end == std::string::npos) {
    end = message.size();
  }
  std::string decoded;
  ABSL_CHECK(
      absl::Base64Unescape(message.substr(start, end - start), &decoded));
  return decoded;
}

std::string GetFirstMimePart(const std::string& contents) {
  const char kBoundary[] = "boundary=\"";
  const char kUnquotedBoundary[] = "boundary=";
  int boundary_start = contents.find(kBoundary);
  int boundary_end;
  if (boundary_start == std::string::npos) {
    boundary_start = contents.find(kUnquotedBoundary);
    ABSL_CHECK_NE(std::string::npos, boundary_start);
    boundary_start += sizeof(kUnquotedBoundary) - 1;
    boundary_end = contents.find_first_of(";\r", boundary_start);
  } else {
    boundary_start += sizeof(kBoundary) - 1;
    boundary_end = contents.find('\"', boundary_start);
  }
  ABSL_CHECK_NE(std::string::npos, boundary_end);
  std::string boundary =
      "--" + contents.substr(boundary_start, boundary_end - boundary_start);

  int part_start = contents.find(boundary, boundary_end);
  ABSL_CHECK_NE(std::string::npos, part_start);
  part_start = contents.find("\r\n", part_start + boundary.size());
  ABSL_CHECK_NE(std::string::npos, part_start);
  part_start += 2;
  int part_end = contents.find(boundary, part_start);
  ABSL_CHECK_NE(std::string::npos, part_end);
  ABSL_CHECK_GT(part_end, part_start + 2);
  // String the CRLF that is right before the boundary end.
  return contents.substr(part_start, part_end - part_start - 2);
}

// Convert an ASN.1 X509 name to a single line string.
std::string CBSToName(const ByteString& raw_name) {
  X509_NAME* name = nullptr;
  const unsigned char* p = CBS_data(raw_name.cbs_ptr());
  d2i_X509_NAME(&name, &p, CBS_len(raw_name.cbs_ptr()));
  std::string line;
  BIO* bio = BIO_new(BIO_s_mem());
  X509_NAME_print_ex(bio, name, 0 /* indent */, 0 /* flags */);
  int size = BIO_pending(bio);
  std::unique_ptr<char[]> buffer(new char[size]);
  ABSL_CHECK_EQ(size, BIO_read(bio, buffer.get(), size));
  line.assign(&buffer[0], size);
  X509_NAME_free(name);
  BIO_free_all(bio);
  return line;
}

X509* PemToCertificate(const std::string& pem) {
  bssl::UniquePtr<BIO> bio(
      BIO_new_mem_buf(const_cast<char*>(pem.data()), pem.size()));
  return PEM_read_bio_X509(bio.get(), nullptr /* existing key */,
                           nullptr /* password callback */,
                           nullptr /* password */);
}

EVP_PKEY* PemToKey(const std::string& pem) {
  bssl::UniquePtr<BIO> bio(
      BIO_new_mem_buf(const_cast<char*>(pem.data()), pem.size()));
  return PEM_read_bio_PrivateKey(bio.get(), nullptr /* existing key */,
                                 nullptr /* password callback */,
                                 nullptr /* password */);
}

std::string NidToDerString(int nid) {
  // Encode the OID as an ASN.1 OBJECT.
  CBB cbb;
  ABSL_CHECK(CBB_init(&cbb, 0));
  ABSL_CHECK(OBJ_nid2cbb(&cbb, nid));
  CBS asn1_cbs;
  CBS_init(&asn1_cbs, CBB_data(&cbb), CBB_len(&cbb));
  // Copy the raw OID into the return value and discard the ASN.1 headers.
  CBS raw_oid_cbs;
  ABSL_CHECK(CBS_get_asn1(&asn1_cbs, &raw_oid_cbs, CBS_ASN1_OBJECT));
  size_t raw_oid_len = CBS_len(&raw_oid_cbs);
  std::string ret(raw_oid_len, '\0');
  ABSL_CHECK(CBS_copy_bytes(
      &raw_oid_cbs, reinterpret_cast<uint8_t*>(ret.data()), raw_oid_len));
  CBB_cleanup(&cbb);
  return ret;
}

}  // namespace credentio_cms
