// Copyright 2022 Google LLC
// SPDX-License-Identifier: BSD-2-Clause

#include <fstream>
#include <iostream>
#include <string>
#include <tuple>

#include "avif/avif.h"
#include "avifincrtest_helpers.h"
#include "aviftest_helpers.h"
#include "gtest/gtest.h"

using testing::Bool;
using testing::Combine;
using testing::Values;

namespace libavif {
namespace {

//------------------------------------------------------------------------------

// Used to pass the data folder path to the GoogleTest suites.
const char* data_path = nullptr;

// Reads the file with file_name into bytes and returns them.
testutil::AvifRwData ReadFile(const char* file_name) {
  std::ifstream file(std::string(data_path) + "/" + file_name,
                     std::ios::binary | std::ios::ate);
  testutil::AvifRwData bytes;
  avifRWDataRealloc(&bytes,
                    file.good() ? static_cast<size_t>(file.tellg()) : 0);
  file.seekg(0, std::ios::beg);
  file.read(reinterpret_cast<char*>(bytes.data),
            static_cast<std::streamsize>(bytes.size));
  return bytes;
}

//------------------------------------------------------------------------------

// Check that non-incremental and incremental decodings of a grid AVIF produce
// the same pixels.
TEST(IncrementalTest, Decode) {
  const testutil::AvifRwData encoded_avif = ReadFile("sofa_grid1x5_420.avif");
  ASSERT_NE(encoded_avif.size, 0u);
  testutil::AvifImagePtr reference(avifImageCreateEmpty(), avifImageDestroy);
  ASSERT_NE(reference, nullptr);
  testutil::AvifDecoderPtr decoder(avifDecoderCreate(), avifDecoderDestroy);
  ASSERT_NE(decoder, nullptr);
  ASSERT_EQ(avifDecoderReadMemory(decoder.get(), reference.get(),
                                  encoded_avif.data, encoded_avif.size),
            AVIF_RESULT_OK);

  // Cell height is hardcoded because there is no API to extract it from an
  // encoded payload.
  testutil::DecodeIncrementally(
      encoded_avif, /*is_persistent=*/true, /*give_size_hint=*/true,
      /*use_nth_image_api=*/false, *reference, /*cell_height=*/154,
      /*enable_fine_incremental_check=*/true);
}

//------------------------------------------------------------------------------

class IncrementalTest
    : public testing::TestWithParam<std::tuple<
          /*width=*/uint32_t, /*height=*/uint32_t, /*create_alpha=*/bool,
          /*flat_cells=*/bool, /*encoded_avif_is_persistent=*/bool,
          /*give_size_hint=*/bool, /*use_nth_image_api=*/bool>> {};

// Encodes then decodes a window of width*height pixels at the middle of the
// image. Check that non-incremental and incremental decodings produce the same
// pixels.
TEST_P(IncrementalTest, EncodeDecode) {
  const uint32_t width = std::get<0>(GetParam());
  const uint32_t height = std::get<1>(GetParam());
  const bool create_alpha = std::get<2>(GetParam());
  const bool flat_cells = std::get<3>(GetParam());
  const bool encoded_avif_is_persistent = std::get<4>(GetParam());
  const bool give_size_hint = std::get<5>(GetParam());
  const bool use_nth_image_api = std::get<6>(GetParam());

  // Load an image. It does not matter that it comes from an AVIF file.
  testutil::AvifImagePtr image(avifImageCreateEmpty(), avifImageDestroy);
  ASSERT_NE(image, nullptr);
  const testutil::AvifRwData image_bytes = ReadFile("sofa_grid1x5_420.avif");
  ASSERT_NE(image_bytes.size, 0u);
  testutil::AvifDecoderPtr decoder(avifDecoderCreate(), avifDecoderDestroy);
  ASSERT_NE(decoder, nullptr);
  ASSERT_EQ(avifDecoderReadMemory(decoder.get(), image.get(), image_bytes.data,
                                  image_bytes.size),
            AVIF_RESULT_OK);

  // Encode then decode it.
  testutil::AvifRwData encoded_avif;
  uint32_t cell_width, cell_height;
  testutil::EncodeRectAsIncremental(*image, width, height, create_alpha,
                                    flat_cells, &encoded_avif, &cell_width,
                                    &cell_height);
  testutil::DecodeNonIncrementallyAndIncrementally(
      encoded_avif, encoded_avif_is_persistent, give_size_hint,
      use_nth_image_api, cell_height, /*enable_fine_incremental_check=*/true);
}

INSTANTIATE_TEST_SUITE_P(WholeImage, IncrementalTest,
                         Combine(/*width=*/Values(1024),
                                 /*height=*/Values(770),
                                 /*create_alpha=*/Values(true),
                                 /*flat_cells=*/Bool(),
                                 /*encoded_avif_is_persistent=*/Values(true),
                                 /*give_size_hint=*/Values(true),
                                 /*use_nth_image_api=*/Values(false)));

// avifEncoderAddImageInternal() only accepts grids of one unique cell, or grids
// where width and height are both at least 64.
INSTANTIATE_TEST_SUITE_P(SingleCell, IncrementalTest,
                         Combine(/*width=*/Values(1),
                                 /*height=*/Values(1),
                                 /*create_alpha=*/Bool(),
                                 /*flat_cells=*/Bool(),
                                 /*encoded_avif_is_persistent=*/Bool(),
                                 /*give_size_hint=*/Bool(),
                                 /*use_nth_image_api=*/Bool()));

// Chroma subsampling requires even dimensions. See ISO 23000-22
// section 7.3.11.4.2.
INSTANTIATE_TEST_SUITE_P(SinglePixel, IncrementalTest,
                         Combine(/*width=*/Values(64, 66),
                                 /*height=*/Values(64, 66),
                                 /*create_alpha=*/Bool(),
                                 /*flat_cells=*/Bool(),
                                 /*encoded_avif_is_persistent=*/Bool(),
                                 /*give_size_hint=*/Bool(),
                                 /*use_nth_image_api=*/Bool()));

//------------------------------------------------------------------------------

}  // namespace
}  // namespace libavif

int main(int argc, char** argv) {
  ::testing::InitGoogleTest(&argc, argv);
  if (argc < 2) {
    std::cerr
        << "The path to the test data folder must be provided as an argument"
        << std::endl;
    return 1;
  }
  libavif::data_path = argv[1];
  return RUN_ALL_TESTS();
}
