// 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 "formats/bmff/extractor.h"

#include <cstdint>
#include <optional>
#include <string>

#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/status/statusor.h"
#include "absl/strings/escaping.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "constants/labels.h"
#include "formats/bmff/box_header.h"
#include "formats/byte_range.h"
#include "jumbf/utils.h"
#include "riegeli/bytes/reader.h"
#include "utils/riegeli.h"

namespace credentio {
namespace {

constexpr absl::string_view kZeroFlags("\x00\x00\x00", 3);
constexpr uint64_t kMaxPayloadSize = 1024 * 1024 * 10;  // 10 MiB

absl::StatusOr<std::string> ReadPurpose(riegeli::Reader& contents) {
  std::string purpose;
  if (!ReadNullTerminatedString(contents, 20, purpose)) {
    return contents.StatusOrAnnotate(absl::DataLossError("kUnexpectedEof"));
  }
  return purpose;
}

struct Result {
  ByteRange location;
  std::string manifest;
};

absl::StatusOr<Result> ExtractManifest(riegeli::Reader& input,
                                       int64_t end_offset) {
  Result result{
      .location{.offset = 0, .length = 0},
      .manifest = "",
  };

  if (!input.SupportsSize() || !input.Size().has_value()) {
    return absl::InvalidArgumentError(
        "manifest store not embedded: reader size cannot be determined");
  }

  uint64_t eof_offset =
      end_offset < 0 ? *input.Size() : static_cast<uint64_t>(end_offset);

  absl::Status iteration_status = IterateOverBmffBoxes(
      input,
      [&input, &eof_offset,
       &result](const BmffBoxHeader& header) -> absl::StatusOr<bool> {
        // Validate that the end of the current box is within the end offset.
        if (header.start + header.box_size > eof_offset) {
          return absl::DataLossError("kUnexpectedEof; truncated BMFF box");
        }
        uint64_t box_end = header.start + header.box_size;

        if (header.type == "mdat" || header.type == "moov") {
          return false;  // Terminate loop
        }

        if (header.type != "uuid" || header.user_type != kC2paBmffBoxUuid) {
          // Skip irrelevant box.
          if (!input.Seek(box_end)) {
            return input.StatusOrAnnotate(
                absl::InternalError("failed to seek to the end of the atom"));
          }
          return true;  // Continue
        }

        // C2PA box
        if (!result.manifest.empty()) {
          return absl::NotFoundError("Multiple manifest stores found");
        }
        if (header.version != 0) {
          return absl::InvalidArgumentError(absl::Substitute(
              "unsupported C2PA box version ($0)", header.version));
        }
        if (header.flags != kZeroFlags) {
          return absl::InvalidArgumentError(
              absl::Substitute("unsupported C2PA box flags ($0)",
                               absl::BytesToHexString(header.flags)));
        }

        ABSL_ASSIGN_OR_RETURN(auto purpose, ReadPurpose(input));
        if (purpose != "manifest") {
          // Ignore non-manifest C2PA boxes.
          if (!input.Seek(box_end)) {
            return input.StatusOrAnnotate(
                absl::InternalError("failed to seek to the end of the atom"));
          }
          return true;  // Continue
        }

        // Skip the merkle offset.
        if (!input.Skip(sizeof(uint64_t))) {
          return input.StatusOrAnnotate(
              absl::DataLossError("kUnexpectedEof; merkle offset"));
        }

        if (box_end < input.pos()) {
          return input.StatusOrAnnotate(
              absl::DataLossError("kUnexpectedEof; payload"));
        }

        uint64_t payload_size = box_end - input.pos();
        if (payload_size > kMaxPayloadSize) {
          return absl::InvalidArgumentError(absl::Substitute(
              "BMFF C2PA box is too large to extract ($0 > $1)", payload_size,
              kMaxPayloadSize));
        }
        result.location = {.offset = header.start,
                           .length = box_end - header.start};
        if (!input.Read(payload_size, result.manifest)) {
          return input.StatusOrAnnotate(
              absl::InternalError("failed to read payload"));
        }

        if (!input.Seek(box_end)) {
          return input.StatusOrAnnotate(
              absl::InternalError("failed to seek to the end of the atom"));
        }
        return true;  // Continue
      });
  if (!iteration_status.ok()) {
    return absl::NotFoundError(
        absl::StrCat("No manifest store found; ", iteration_status.message()));
  }
  if (result.manifest.empty()) {
    return absl::NotFoundError("No manifest store found");
  }
  return result;
}

}  // namespace

absl::StatusOr<std::string> BmffExtractor::ExtractManifestStore(
    riegeli::Reader& input) const {
  ABSL_ASSIGN_OR_RETURN(auto result, ExtractManifest(input, /*end_offset=*/-1));
  return result.manifest;
}

absl::StatusOr<std::optional<ByteRange>>
BmffExtractor::ExtractManifestStoreLocation(riegeli::Reader& input,
                                            ExtractOptions options) const {
  auto result = ExtractManifest(input, options.end_offset);
  if (!result.ok()) {
    if (options.requires_c2pa) {
      return result.status();
    }
    return std::nullopt;
  }
  return (*result).location;
}

bool BmffExtractor::MightBeC2paManifestStore(absl::string_view payload) const {
  return jumbf::HasDescriptionBoxMatching(payload, kManifestStoreUuid,
                                          kMinimumJumbfDescriptionToggles,
                                          kManifestStoreLabel)
      .value_or(false);
}

}  // namespace credentio
