// 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 "claim/generator.h"

#include <memory>
#include <utility>

#include "absl/base/nullability.h"
#include "absl/functional/any_invocable.h"
#include "absl/log/die_if_null.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "assertion/assertion_encoder.h"
#include "assertion/assertion_referencer.h"
#include "async/async_context.h"
#include "claim/claim_cbor_encoder.h"
#include "claim/manifest_box.h"
#include "claim/manifest_box_assembler.h"
#include "claim/manifest_box_encoder.h"
#include "claim/signer.h"
#include "crypto/hash.h"
#include "proto/actions_assertion.pb.h"
#include "proto/assertion.pb.h"
#include "proto/bmff_based_hash_assertion.pb.h"
#include "proto/boxes_hash_assertion.pb.h"
#include "proto/data_hash_assertion.pb.h"
#include "proto/generator.pb.h"
#include "proto/generator_info.pb.h"
#include "proto/hashed_uri.pb.h"
#include "proto/manifest.pb.h"

namespace credentio {
namespace {

ClaimSigner::Options ToClaimSignerOptions(
    const GenerateManifestStoreOptions& options, AsyncContext context) {
  ClaimSigner::Options result;
  result.async_context = std::move(context);
  switch (options.time_stamping_mode()) {
    case GenerateManifestStoreOptions::TIME_STAMPING_REQUIRED:
      result.time_stamping_mode = TimeStampingMode::kRequired;
      break;
    case GenerateManifestStoreOptions::TIME_STAMPING_OMITTED_WITH_PADDING:
      result.time_stamping_mode = TimeStampingMode::kOmittedWithPadding;
      break;
    case GenerateManifestStoreOptions::TIME_STAMPING_OPTIONAL:
    case GenerateManifestStoreOptions::TIME_STAMPING_MODE_UNSPECIFIED:
    default:
      result.time_stamping_mode = TimeStampingMode::kOptional;
      break;
  }
  return result;
}

class ManifestEncoderImpl : public ManifestEncoder {
 public:
  explicit ManifestEncoderImpl(
      GeneratorInfo generator_info,
      const HasherFactory* absl_nonnull hash_factory,
      ClaimSigner* absl_nonnull claim_signer,
      const AssertionEncoder* absl_nonnull assertion_cbor_encoder,
      const ClaimCborEncoder* absl_nonnull claim_cbor_encoder)
      : generator_info_(std::move(generator_info)),
        hash_factory_(*ABSL_DIE_IF_NULL(hash_factory)),
        claim_signer_(*ABSL_DIE_IF_NULL(claim_signer)),
        assertion_cbor_encoder_(*ABSL_DIE_IF_NULL(assertion_cbor_encoder)),
        claim_cbor_encoder_(*ABSL_DIE_IF_NULL(claim_cbor_encoder)) {}

  void Encode(ManifestBox* absl_nonnull manifest,
              const GenerateManifestStoreOptions& options, AsyncContext context,
              absl::AnyInvocable<void(absl::StatusOr<ManifestEncoderResult>) &&>
                  cb) const override {
    auto assertion_reference =
        std::make_shared<AssertionReferencer>(&hash_factory_);
    auto manifest_box_encoder = std::make_shared<ManifestBoxEncoder>(
        assertion_reference.get(), &generator_info_, &claim_signer_,
        &assertion_cbor_encoder_, &claim_cbor_encoder_, manifest,
        hash_factory_.algorithm());
    manifest_box_encoder->Encode(
        ToClaimSignerOptions(options, std::move(context)),
        [assertion_reference, manifest_box_encoder, cb = std::move(cb)](
            absl::StatusOr<ManifestEncoderResult> result) mutable {
          std::move(cb)(std::move(result));
        });
  }

 private:
  GeneratorInfo generator_info_;
  const HasherFactory& hash_factory_;
  ClaimSigner& claim_signer_;
  const AssertionEncoder& assertion_cbor_encoder_;
  const ClaimCborEncoder& claim_cbor_encoder_;
};
}  // namespace

absl::StatusOr<std::unique_ptr<ManifestBoxAssembler>> CreateManifestAssembler(
    const CreateManifestAssemblerOptions& options) {
  return std::make_unique<StandardManifestBoxAssembler>(
      options.uuid_generator, options.hash_factory, options.spec_version);
}

absl::StatusOr<std::unique_ptr<ManifestEncoder>> CreateManifestEncoder(
    const CreateManifestEncoderOptions& options) {
  return std::make_unique<ManifestEncoderImpl>(
      options.generator_info, options.hash_factory, options.claim_signer,
      options.assertion_cbor_encoder, options.claim_cbor_encoder);
}
}  // namespace credentio
