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

#include <string>
#include <utility>
#include <vector>

#include "absl/container/flat_hash_map.h"
#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/status/statusor.h"
#include "absl/strings/cord.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "assertion/assertion_referencer.h"
#include "async/async_context.h"
#include "claim/signer.h"
#include "constants/labels.h"
#include "jumbf/box_builder.h"
#include "jumbf/constants.h"
#include "proto/actions_assertion.pb.h"
#include "proto/assertion.pb.h"
#include "proto/generator_info.pb.h"
#include "proto/hashed_uri.pb.h"
#include "proto/manifest.pb.h"
#include "proto/multi_asset_hash_assertion.pb.h"
#include "uuid/uuid.h"

namespace credentio {
namespace {

absl::StatusOr<jumbf::BuiltSuperBox> SerializeAssertionStore(
    std::vector<jumbf::BuiltSuperBox> assertions) {
  jumbf::SuperBoxBuilder assertion_store_builder(
      kAssertionStoreUuid, {.label = absl::Cord(kAssertionStoreLabel)});
  for (jumbf::BuiltSuperBox& assertion_box : assertions) {
    ABSL_RETURN_IF_ERROR(
        assertion_store_builder.AddChild(std::move(assertion_box)));
  }
  return std::move(assertion_store_builder).Finalize();
}

absl::StatusOr<jumbf::BuiltSuperBox> SerializeCborSuperBox(
    const Uuid& uuid, absl::string_view label, absl::Cord cbor_content) {
  jumbf::SuperBoxBuilder builder(uuid, {.label = absl::Cord(label)});
  ABSL_RETURN_IF_ERROR(
      builder.AddContent(jumbf::kCborBoxType, std::move(cbor_content)));
  return std::move(builder).Finalize();
}

struct SignatureBoxResult {
  jumbf::BuiltSuperBox box;
};

void MakeSignatureBox(
    absl::string_view claim_cbor, const ClaimSigner& claim_signer,
    const ClaimSigner::Options& options,
    absl::AnyInvocable<void(absl::StatusOr<SignatureBoxResult>) &&> cb) {
  AsyncResolver<SignatureBoxResult> resolver(options.async_context,
                                             std::move(cb));
  auto done_cb =
      [resolver = std::move(resolver)](
          absl::StatusOr<ClaimSigner::SignResult> signature_status) mutable {
        if (!signature_status.ok()) {
          resolver.Return(signature_status.status());
          return;
        }
        absl::StatusOr<jumbf::BuiltSuperBox> signature_box =
            SerializeCborSuperBox(
                kClaimSignatureUuid, kClaimSignatureLabel,
                absl::Cord(std::move(signature_status->signature)));
        if (!signature_box.ok()) {
          resolver.Return(signature_box.status());
          return;
        }
        resolver.Return(SignatureBoxResult{
            .box = std::move(*signature_box),
        });
      };
  claim_signer.Sign(claim_cbor, options, std::move(done_cb));
}

}  // namespace

absl::Status ManifestBoxEncoder::PopulateMultiAssetPartHashes(
    MultiAssetHashAssertion* assertion) const {
  for (auto& part : *assertion->mutable_parts()) {
    absl::string_view url = part.hash_assertion().url();
    auto it = assertion_url_to_index_.find(url);
    if (it == assertion_url_to_index_.end()) {
      return absl::InternalError(
          absl::StrCat("Could not find hash for url: ", url));
    }
    *part.mutable_hash_assertion() = assertion_hashed_uris_[it->second];
  }
  return absl::OkStatus();
}

absl::Status ManifestBoxEncoder::AddAssertion(Assertion& assertion) {
  if (assertion.has_multi_asset_hash()) {
    ABSL_RETURN_IF_ERROR(
        PopulateMultiAssetPartHashes(assertion.mutable_multi_asset_hash()));
  }

  ABSL_ASSIGN_OR_RETURN(jumbf::BuiltSuperBox assertion_box,
                        assertion_encoder_.ToJumbf(assertion));
  ABSL_ASSIGN_OR_RETURN(HashedUri assertion_hashed_uri,
                        assertion_reference_.Generate(assertion_box));
  assertion_url_to_index_[assertion_hashed_uri.url()] =
      assertion_hashed_uris_.size();
  assertion_hashed_uris_.Add(std::move(assertion_hashed_uri));
  assertion_boxes_.push_back(std::move(assertion_box));
  return absl::OkStatus();
}

absl::Status ManifestBoxEncoder::AddActionsAssertion(Assertion assertion) {
  for (ActionItem& action : *assertion.mutable_actions()->mutable_actions()) {
    if (action.action() == "c2pa.opened" &&
        action.parameters().ingredients_size() != 1) {
      return absl::InvalidArgumentError(
          "Opened action must have exactly one ingredient.");
    }
    if (action.parameters().ingredients_size() != 0) {
      for (auto& ingredient :
           *action.mutable_parameters()->mutable_ingredients()) {
        auto it = assertion_url_to_index_.find(ingredient.url());
        if (it == assertion_url_to_index_.end()) {
          return absl::InternalError(absl::StrCat(
              "Could not find hash for ingredient url: ", ingredient.url()));
        }
        ingredient = assertion_hashed_uris_[it->second];
      }
    }
    if (action.parameters().has_redacted_uri()) {
      redacted_assertions_.emplace_back(action.parameters().redacted_uri());
    }
  }
  return AddAssertion(assertion);
}

absl::Status ManifestBoxEncoder::AddGatheredAssertion(
    const GatheredAssertion& gathered_assertion) {
  if (gathered_assertion.content_type() !=
      GatheredAssertion::CONTENT_TYPE_JSON) {
    return absl::InvalidArgumentError(
        "Gathered assertion content type must be JSON.");
  }
  jumbf::SuperBoxBuilder builder(
      jumbf::kJsonBoxTypeUuid,
      {.label = absl::Cord(gathered_assertion.label())});
  ABSL_RETURN_IF_ERROR(builder.AddContent(
      jumbf::kJsonBoxType, absl::Cord(gathered_assertion.data())));
  ABSL_ASSIGN_OR_RETURN(jumbf::BuiltSuperBox assertion_box,
                        std::move(builder).Finalize());
  ABSL_ASSIGN_OR_RETURN(HashedUri assertion_hashed_uri,
                        assertion_reference_.Generate(assertion_box));
  gathered_assertion_hashed_uris_.Add(std::move(assertion_hashed_uri));
  assertion_boxes_.push_back(std::move(assertion_box));
  return absl::OkStatus();
}

absl::Status ManifestBoxEncoder::AddAssertions() {
  // Note that we must add an assertion before adding any other assertion that
  // references it, so the referenced assertion's hash is available. So, for
  // example, ingredient assertions must be added before actions assertions
  // since some actions assertions reference ingredient assertions.
  for (Assertion& assertion : manifest_.ingredient_assertions) {
    ABSL_RETURN_IF_ERROR(AddAssertion(assertion));
  }
  ABSL_RETURN_IF_ERROR(AddActionsAssertion(manifest_.actions_assertion));
  ABSL_RETURN_IF_ERROR(AddAssertion(manifest_.hard_binding_assertion));
  for (Assertion& assertion : manifest_.part_hash_assertions) {
    ABSL_RETURN_IF_ERROR(AddAssertion(assertion));
  }
  if (manifest_.multi_part_assertion.has_value()) {
    ABSL_RETURN_IF_ERROR(AddAssertion(*manifest_.multi_part_assertion));
  }
  for (const auto& gathered_assertion : manifest_.gathered_assertions) {
    ABSL_RETURN_IF_ERROR(AddGatheredAssertion(gathered_assertion));
  }
  return absl::OkStatus();
}

void ManifestBoxEncoder::EncodeClaimAndSignature(
    const ClaimSigner::Options& options,
    absl::AnyInvocable<void(absl::StatusOr<ManifestEncoderResult>) &&> cb) {
  AsyncResolver<ManifestEncoderResult> resolver(options.async_context,
                                                std::move(cb));
  Claim claim;
  claim.set_instance_id(manifest_.instance_id);
  *claim.mutable_claim_generator_info() = generator_info_;
  claim.mutable_created_assertions()->Swap(&assertion_hashed_uris_);
  claim.mutable_gathered_assertions()->Swap(&gathered_assertion_hashed_uris_);
  for (const std::string& redacted_assertion : redacted_assertions_) {
    *claim.add_redacted_assertions() = redacted_assertion;
  }
  claim.set_signature(kClaimSignatureUrl);
  claim.set_default_algorithm(absl::StrCat(hash_algorithm_));

  auto prepare_claim = [&]() -> absl::StatusOr<std::string> {
    ABSL_ASSIGN_OR_RETURN(std::string claim_cbor,
                          claim_cbor_encoder_.ToCbor(claim));
    ABSL_ASSIGN_OR_RETURN(jumbf::BuiltSuperBox claim_box,
                          SerializeCborSuperBox(kClaimUuid, kClaimV2Label,
                                                absl::Cord(claim_cbor)));
    ABSL_RETURN_IF_ERROR(manifest_builder_.AddChild(std::move(claim_box)));
    return claim_cbor;
  };
  absl::StatusOr<std::string> claim_cbor = prepare_claim();
  if (!claim_cbor.ok()) {
    resolver.Return(claim_cbor.status());
    return;
  }
  auto done_cb =
      [this, resolver = std::move(resolver)](
          absl::StatusOr<SignatureBoxResult> claim_signature) mutable {
        auto finalize_manifest =
            [&]() -> absl::StatusOr<ManifestEncoderResult> {
          ABSL_RETURN_IF_ERROR(claim_signature.status());
          ABSL_RETURN_IF_ERROR(
              manifest_builder_.AddChild(std::move(claim_signature->box)));
          ABSL_ASSIGN_OR_RETURN(jumbf::BuiltSuperBox active_manifest,
                                std::move(manifest_builder_).Finalize());
          ABSL_ASSIGN_OR_RETURN(jumbf::BuiltSuperBox finalized_manifest_store,
                                std::move(manifest_.manifest_store_builder)
                                    .Finalize(std::move(active_manifest)));
          return ManifestEncoderResult{
              .box = std::move(finalized_manifest_store),
          };
        };
        resolver.Return(finalize_manifest());
      };
  MakeSignatureBox(*claim_cbor, claim_signer_, options, std::move(done_cb));
}

absl::Status ManifestBoxEncoder::EncodeAssertionStore() {
  ABSL_ASSIGN_OR_RETURN(jumbf::BuiltSuperBox assertion_store,
                        SerializeAssertionStore(std::move(assertion_boxes_)));
  return manifest_builder_.AddChild(std::move(assertion_store));
}

void ManifestBoxEncoder::Encode(
    const ClaimSigner::Options& options,
    absl::AnyInvocable<void(absl::StatusOr<ManifestEncoderResult>) &&> cb) {
  auto add_assertions_status = AddAssertions();
  if (!add_assertions_status.ok()) {
    std::move(cb)(add_assertions_status);
    return;
  }
  auto encode_assertion_store_status = EncodeAssertionStore();
  if (!encode_assertion_store_status.ok()) {
    std::move(cb)(encode_assertion_store_status);
    return;
  }
  EncodeClaimAndSignature(options, std::move(cb));
}
}  // namespace credentio
