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

#include <cstddef>
#include <cstdint>
#include <string>
#include <utility>

#include "absl/status/status.h"
#include "absl/status/status_macros.h"
#include "absl/status/statusor.h"
#include "absl/strings/string_view.h"
#include "absl/strings/substitute.h"
#include "absl/types/span.h"
#include "constants/labels.h"
#include "formats/jpeg/reader.h"
#include "jumbf/box.h"
#include "jumbf/constants.h"
#include "jumbf/parse.h"
#include "riegeli/bytes/reader.h"

namespace credentio {
namespace {

constexpr uint64_t kMaxPayloadSize = 1024 * 1024 * 10;  // 10 MiB
constexpr size_t kMaxSegmentsPerId = 1000;

bool IsValidNextSegment(const JpegSegment& prev_segment,
                        const JpegSegment& curr_segment) {
  if (!prev_segment.app11_info.has_value() ||
      !curr_segment.app11_info.has_value()) {
    // Missing APP11 information, invalid.
    return false;
  }
  if (!prev_segment.app11_info->jumbf_data.has_value() ||
      !curr_segment.app11_info->jumbf_data.has_value()) {
    // Segments do not contain JUMBF data, invalid.
    return false;
  }

  // C2PA Spec requires sequence numbers to be increasing.
  if (prev_segment.app11_info->sequence_number >=
      curr_segment.app11_info->sequence_number) {
    // Sequence number is not increasing, invalid.
    return false;
  }

  // C2PA Spec requires segments to be contiguous.
  if ((prev_segment.offset + prev_segment.length) != curr_segment.offset) {
    // Segments are not contiguous, invalid.
    return false;
  }

  // All segments must have the same lbox and xlbox.
  if (prev_segment.app11_info->jumbf_data->lbox !=
      curr_segment.app11_info->jumbf_data->lbox) {
    // Lbox is different, invalid.
    return false;
  }
  if (prev_segment.app11_info->jumbf_data->xlbox !=
      curr_segment.app11_info->jumbf_data->xlbox) {
    // Xlbox is different, invalid.
    return false;
  }

  return true;
}

absl::StatusOr<std::string> ExtractCompletePayload(
    riegeli::Reader& input, absl::Span<const JpegSegment> segments) {
  if (segments.empty() || !segments.front().app11_info.has_value() ||
      !segments.front().app11_info->jumbf_data.has_value()) {
    return "";
  }
  uint64_t expected_payload_size =
      segments.front().app11_info->jumbf_data->lbox == 1
          ? segments.front().app11_info->jumbf_data->xlbox
          : segments.front().app11_info->jumbf_data->lbox;
  if (expected_payload_size == 0 || expected_payload_size > kMaxPayloadSize) {
    return absl::InvalidArgumentError(absl::Substitute(
        "Declared JUMBF payload size is invalid ($0)", expected_payload_size));
  }

  std::string payload;
  for (const JpegSegment& segment : segments) {
    if (!segment.app11_info.has_value() ||
        !segment.app11_info->jumbf_data.has_value()) {
      // Segment does not contain JUMBF data within an APP11 segment, skip it.
      continue;
    }

    uint64_t payload_offset = segment.app11_info->payload_offset;
    uint64_t payload_length = segment.app11_info->payload_length;
    if (!payload.empty()) {
      // This is not the first segment, so skip the JUMBF header data
      payload_offset = segment.app11_info->jumbf_data->payload_offset;
      payload_length = segment.app11_info->jumbf_data->payload_length;
    }

    if (payload.size() + payload_length > kMaxPayloadSize) {
      return absl::InvalidArgumentError(
          absl::Substitute("JPEG segment is too large to extract ($0 > $1)",
                           payload.size() + payload_length, kMaxPayloadSize));
    }

    if (!input.Seek(payload_offset) || input.pos() != payload_offset) {
      return absl::InvalidArgumentError("Failed to seek to payload offset");
    }

    std::string segment_payload;
    if (!input.Read(payload_length, segment_payload)) {
      return input.StatusOrAnnotate(
          absl::DataLossError("Failed to read payload"));
    }
    payload.append(segment_payload);
  }

  if (payload.size() != expected_payload_size) {
    // Incomplete payload, return empty string.
    return "";
  }

  return payload;
}

bool IsC2paManifestStore(absl::string_view payload) {
  absl::StatusOr<jumbf::SuperBox> box =
      jumbf::ConsumeSuperBox(&payload, /*recursion_limit=*/0);
  if (!box.ok()) {
    // If we can't read a JUMBF Superbox, it's not a C2PA Manifest Store,
    // ignore.
    return false;
  }

  if (box->description.type_uuid != kManifestStoreUuid) {
    // JUMBF Superbox is not a C2PA Manifest Store, ignore.
    return false;
  };

  if (!box->description.requestable) {
    // Manifest store must be requestable.
    return false;
  }

  return box->description.label == kManifestStoreLabel;
}

}  // namespace

void C2paSegmentHandler::RecordSegment(JpegSegment segment) {
  if (!segment.app11_info.has_value() ||
      !segment.app11_info->jumbf_data.has_value()) {
    // Segment does not contain APP11 information, skip it.
    return;
  }

  const JpegApp11Segment& app11_info = *segment.app11_info;
  const JpegJumbfData& jumbf_data = *app11_info.jumbf_data;

  if (ignored_segment_ids_.contains(app11_info.segment_id)) {
    // Already ignored this segment ID, skip it.
    return;
  }

  if (app11_info.segment_id == 0) {
    // Invalid segment id, skip it.
    return;
  }

  if (jumbf_data.tbox != jumbf::kSuperBoxType) {
    // Segment is not a JUMBF Superbox, skip it.
    return;
  }

  auto [it, inserted] = segment_map_.try_emplace(app11_info.segment_id);
  if (inserted) {
    // First segment for this segment ID, record it.
    it->second.push_back(std::move(segment));
  } else {
    // Segment ID already exists.
    if (it->second.size() >= kMaxSegmentsPerId ||
        !IsValidNextSegment(it->second.back(), segment)) {
      // Exceeded max segments per ID or invalid continuing segment, remove from
      // map and ignore.
      segment_map_.erase(it);
      ignored_segment_ids_.insert(app11_info.segment_id);
    } else {
      // Valid continuing segment, record it.
      it->second.push_back(std::move(segment));
    }
  }
}

absl::StatusOr<C2paSegmentHandler::Segment> C2paSegmentHandler::GetC2paSegment(
    riegeli::Reader& input) const {
  C2paSegmentHandler::Segment result;
  int64_t c2pa_count = 0;

  for (const auto& [segment_id, segments] : segment_map_) {
    if (segments.empty()) {
      continue;
    }
    ABSL_ASSIGN_OR_RETURN(std::string payload,
                          ExtractCompletePayload(input, segments));
    if (payload.empty()) {
      // Incomplete payload, ignore.
      continue;
    }

    if (IsC2paManifestStore(payload)) {
      ++c2pa_count;
      if (c2pa_count > 1) {
        return absl::NotFoundError("Multiple manifest stores found");
      }

      result.manifest_store = std::move(payload);
      result.segment = JpegSegment{
          .offset = segments.front().offset,
          .marker_label = "C2PA",
          .length = (segments.back().offset - segments.front().offset) +
                    segments.back().length,
      };
    }
  }

  if (c2pa_count == 0) {
    return absl::NotFoundError("No manifest store found");
  }
  return std::move(result);
}

}  // namespace credentio
