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

#include <cstdint>
#include <memory>
#include <optional>
#include <utility>
#include <vector>

#include "absl/base/nullability.h"
#include "absl/log/die_if_null.h"
#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "bindings/binding_hasher.h"
#include "constants/status_codes.h"
#include "formats/asset_byte_info.h"
#include "formats/byte_range.h"
#include "proto/assertion.pb.h"
#include "proto/data_hash_assertion.pb.h"
#include "proto/validation_result.pb.h"
#include "riegeli/bytes/reader.h"
#include "utils/dual_status_tracker.h"
#include "utils/status_tracker.h"
#include "validator/result.h"
#include "validator/validation_result_internal.h"

namespace credentio {

namespace {
class DataHashBindingHasherTracker : public BindingHasherTracker {
 public:
  explicit DataHashBindingHasherTracker(StatusTracker* tracker,
                                        absl::string_view hard_binding_uri)
      : tracker_(*ABSL_DIE_IF_NULL(tracker)),
        hard_binding_uri_(hard_binding_uri) {}
  void RecordMismatch() override {
    tracker_.RecordFailure(FailureStatusCode::kAssertionDataHashMismatch,
                           {.url = hard_binding_uri_});
  }
  void RecordMalformed() override {
    tracker_.RecordFailure(FailureStatusCode::kAssertionDataHashMalformed,
                           {.url = hard_binding_uri_});
  }
  void RecordAlgorithmUnsupported() override {
    tracker_.RecordFailure(FailureStatusCode::kAlgorithmUnsupported,
                           {.url = hard_binding_uri_});
  }
  void RecordGeneralError(absl::Status error) override {
    tracker_.RecordFailure(
        FailureStatusCode::kGeneralError,
        {.url = hard_binding_uri_, .explanation = error.message()});
  }

 private:
  StatusTracker& tracker_;
  absl::string_view hard_binding_uri_;
};
}  // namespace

absl::StatusOr<std::unique_ptr<ValidationResultProto>>
DataHashHardBindingValidator::Validate(
    riegeli::Reader& contents, const AssetByteInfo& asset_byte_info,
    std::unique_ptr<PartialValidationResultProto> partial_validation_result)
    const {
  const Assertion* absl_nullable assertion =
      GetAssertion(partial_validation_result.get(),
                   partial_validation_result->hard_binding_uri());
  if (assertion == nullptr) {
    return absl::InvalidArgumentError(absl::StrCat(
        "missing assertion: ", partial_validation_result->hard_binding_uri()));
  }
  if (!assertion->has_data_hash()) {
    return absl::InvalidArgumentError(
        absl::StrCat("assertion is not a data hash assertion: ",
                     partial_validation_result->hard_binding_uri()));
  }

  ABSL_ASSIGN_OR_RETURN(auto tracker,
                        DualStatusTracker::FromPartialValidationResult(
                            partial_validation_result.get()));
  Validate(contents, asset_byte_info.manifest_store_location,
           assertion->data_hash(),
           partial_validation_result->hard_binding_uri(), *tracker,
           tracker->WritesToIngredientManifest());

  return MakeFullValidationResult(std::move(partial_validation_result));
}

void DataHashHardBindingValidator::Validate(
    riegeli::Reader& contents, std::optional<ByteRange> manifest_store_location,
    const DataHashAssertion& assertion, absl::string_view hard_binding_uri,
    StatusTracker& tracker, bool assertion_in_ingredient_manifest,
    uint64_t start_offset, int64_t end_offset) const {
  std::vector<BindingHasher::Chunk> exclusions;

  if (!contents.SupportsSize() || !contents.Size().has_value()) {
    tracker.RecordFailure(FailureStatusCode::kGoogleInternalError,
                          {.url = hard_binding_uri,
                           .explanation = "Asset size cannot be determined"});
    return;
  }

  const int64_t c2pa_start = manifest_store_location.has_value()
                                 ? manifest_store_location->offset
                                 : -1;
  const uint64_t asset_end_offset =
      end_offset == -1 ? *contents.Size() : end_offset;

  uint64_t valid_next_exclusion_start = start_offset;
  int64_t offset_adjustment = 0;
  bool has_additional_exclusions = assertion.exclusions_size() > 1;
  for (const auto& exclusion : assertion.exclusions()) {
    if (exclusion.start() < 0 || exclusion.length() < 0) {
      tracker.RecordFailure(FailureStatusCode::kAssertionDataHashMalformed,
                            {.url = hard_binding_uri});
      return;
    }
    const uint64_t ex_start =
        start_offset + exclusion.start() + offset_adjustment;
    int64_t ex_length = exclusion.length();
    if (assertion_in_ingredient_manifest && ex_start == c2pa_start) {
      // Note: fluffy_puppy.webp manifest exclusion range is 1 byte shorter than
      // the box and if this case is triggered, it would fail validation.
      ex_length = manifest_store_location->length;
      offset_adjustment = manifest_store_location->length - exclusion.length();
    }

    // ex_start is now with respect to the start of the file
    if (ex_start < start_offset || exclusion.length() < 0) {
      // Starts before the start of this asset or negative length.
      tracker.RecordFailure(FailureStatusCode::kAssertionDataHashMalformed,
                            {.url = hard_binding_uri});
      return;
    }
    if (ex_start < valid_next_exclusion_start) {
      // Starts before the end of the previous exclusion range.
      tracker.RecordFailure(FailureStatusCode::kAssertionDataHashMalformed,
                            {.url = hard_binding_uri});
      return;
    }
    valid_next_exclusion_start = ex_start + ex_length;

    if (ex_start + ex_length > asset_end_offset) {
      // Ends past the end of the asset.
      tracker.RecordFailure(FailureStatusCode::kAssertionDataHashMismatch,
                            {.url = hard_binding_uri});
      return;
    }

    exclusions.push_back({.op = BindingHasher::Chunk::Op::kExclusion,
                          .offset = ex_start,
                          .length = ex_length});

    if (ex_start < c2pa_start) {
      has_additional_exclusions = true;
    }
  }
  if (manifest_store_location.has_value() && has_additional_exclusions) {
    tracker.RecordInformational(
        InformationalStatusCode::kAssertionDataHashAdditionalExclusionsPresent,
        {.url = hard_binding_uri});
  }

  DataHashBindingHasherTracker data_hash_tracker(&tracker, hard_binding_uri);
  auto hasher =
      BindingHasher::Create(assertion.alg(), exclusions, data_hash_tracker);
  if (hasher == nullptr) {
    return;
  }

  auto digest =
      hasher->Digest(contents, data_hash_tracker, start_offset, end_offset);
  if (!digest.has_value()) {
    return;
  }

  if (*digest != assertion.hash()) {
    tracker.RecordFailure(FailureStatusCode::kAssertionDataHashMismatch,
                          {.url = hard_binding_uri});
    return;
  }

  tracker.RecordSuccess(SuccessStatusCode::kAssertionDataHashMatch,
                        {.url = hard_binding_uri});
}

}  // namespace credentio
