// 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);
}

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

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);
}

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();
}
