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

#include <sys/types.h>

#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/ascii.h"
#include "absl/strings/str_cat.h"
#include "formats/png/constants.h"
#include "riegeli/bytes/reader.h"
#include "riegeli/endian/endian_reading.h"

namespace credentio {

namespace {

absl::StatusOr<PngChunk> ReadHeader(riegeli::Reader& reader) {
  uint64_t start_offset = reader.pos();
  std::string header;
  if (!reader.Read(kPngHeader.size(), header)) {
    return reader.StatusOrAnnotate(
        absl::InvalidArgumentError("Failed to read header"));
  }
  if (header != kPngHeader) {
    return absl::InvalidArgumentError("input does not start with PNG marker");
  }
  return PngChunk{
      .offset = start_offset,
      .length = kPngHeader.size(),
      .type = kPngChunkTypeHeader.data(),
      .data_length = static_cast<uint32_t>(kPngHeader.size()),
  };
}

bool ChunkGoesPastEndOffset(uint64_t chunk_start, uint64_t chunk_length,
                            uint64_t end_offset) {
  if (end_offset < chunk_length) {
    // Chunk is larger than the file size
    return true;
  }
  if (chunk_start > (end_offset - chunk_length)) {
    // Chunk starts too far into the file to read the entire chunk.
    return true;
  }
  return false;
}

absl::StatusOr<PngChunk> ReadChunk(riegeli::Reader& reader,
                                   int64_t end_offset) {
  PngChunk chunk{.offset = reader.pos()};
  if (!riegeli::ReadBigEndian<uint32_t>(reader, chunk.data_length)) {
    return reader.StatusOrAnnotate(
        absl::DataLossError("Failed to read chunk data length"));
  }
  chunk.length = sizeof(uint32_t)                            // Chunk length
                 + sizeof(uint32_t)                          // Chunk type
                 + static_cast<uint64_t>(chunk.data_length)  // Chunk data
                 + sizeof(uint32_t);                         // CRC
  if (ChunkGoesPastEndOffset(chunk.offset, chunk.length, end_offset)) {
    return absl::InvalidArgumentError(
        "PNG chunk extends beyond the end of the file");
  }
  if (!reader.Read(4, chunk.type)) {
    return reader.StatusOrAnnotate(
        absl::DataLossError("Failed to read chunk type"));
  }
  for (char c : chunk.type) {
    if (!absl::ascii_isalpha(c)) {
      return absl::InvalidArgumentError(
          absl::StrCat("Invalid PNG chunk type name: ", chunk.type));
    }
  }
  return std::move(chunk);
}

}  // namespace

absl::Status IterateOverPngChunks(riegeli::Reader& reader,
                                  PngChunkProcessor processor) {
  if (!reader.SupportsSize() || !reader.Size().has_value()) {
    return absl::InvalidArgumentError(
        "PNG reader does not support size, cannot iterate");
  }
  uint64_t end_offset = *reader.Size();
  if (kPngMinimumAssetSize > end_offset - reader.pos()) {
    // Asset size is smaller than the minimum size needed, just return.
    return absl::OkStatus();
  }

  ABSL_ASSIGN_OR_RETURN(PngChunk header, ReadHeader(reader));

  ABSL_RETURN_IF_ERROR(processor(header));
  uint64_t last_chunk_offset = header.offset;
  while (reader.pos() < end_offset) {
    ABSL_ASSIGN_OR_RETURN(PngChunk chunk, ReadChunk(reader, end_offset));

    if (chunk.offset <= last_chunk_offset) {
      return reader.StatusOrAnnotate(
          absl::InvalidArgumentError("PNG chunk offset did not advance"));
    }
    last_chunk_offset = chunk.offset;

    ABSL_RETURN_IF_ERROR(processor(chunk));
    if (!reader.Seek(chunk.offset + chunk.length)) {
      return reader.StatusOrAnnotate(
          absl::InvalidArgumentError("Failed to seek to next chunk"));
    }

    if (chunk.type == kPngChunkTypeEnd) {
      break;
    }
  }

  if (reader.pos() < end_offset) {
    PngChunk chunk{
        .offset = reader.pos(),
        .length = end_offset - reader.pos(),
        .type = "c2pa.after",
        .data_length = 0,
    };
    ABSL_RETURN_IF_ERROR(processor(chunk));
  }
  return absl::OkStatus();
}

}  // namespace credentio
