/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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
 *
 *    http://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 "memory/VeloxColumnarBatch.h"
#include "memory/VeloxMemoryManager.h"
#include "operators/serializer/VeloxColumnarToRowConverter.h"
#include "operators/serializer/VeloxRowToColumnarConverter.h"
#include "velox/vector/tests/utils/VectorTestBase.h"

#include <gtest/gtest.h>

using namespace facebook;
using namespace facebook::velox;

namespace gluten {

class VeloxColumnarToRowTest : public ::testing::Test, public test::VectorTestBase {
 protected:
  static void SetUpTestCase() {
    memory::MemoryManager::testingSetInstance({});
  }

  void testRowBufferAddr(velox::RowVectorPtr vector, uint8_t* expectArr, int32_t expectArrSize) {
    auto columnarToRowConverter = std::make_shared<VeloxColumnarToRowConverter>(pool_, 64 << 10);

    auto cb = std::make_shared<VeloxColumnarBatch>(vector);
    columnarToRowConverter->convert(cb);

    uint8_t* address = columnarToRowConverter->getBufferAddress();
    for (int i = 0; i < expectArrSize; i++) {
      ASSERT_EQ(*(address + i), *(expectArr + i));
    }
  }
};

TEST_F(VeloxColumnarToRowTest, Buffer_int8_int16) {
  auto vector = makeRowVector({makeFlatVector<int8_t>({1, 2}), makeFlatVector<int16_t>({1, 2})});
  uint8_t expectArr[] = {
      0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
  };
  testRowBufferAddr(vector, expectArr, sizeof(expectArr));
}

TEST_F(VeloxColumnarToRowTest, Buffer_int32_int64) {
  auto vector = makeRowVector({makeFlatVector<int32_t>({1, 2}), makeFlatVector<int64_t>({1, 2})});
  uint8_t expectArr[] = {
      0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
  };
  testRowBufferAddr(vector, expectArr, sizeof(expectArr));
}

TEST_F(VeloxColumnarToRowTest, Buffer_float_double) {
  auto vector = makeRowVector({makeFlatVector<float>({1.0, 2.0}), makeFlatVector<double>({1.0, 2.0})});

  uint8_t expectArr[] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 63, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 240, 63,
                         0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,   64};
  testRowBufferAddr(vector, expectArr, sizeof(expectArr));
}

TEST_F(VeloxColumnarToRowTest, Buffer_bool_string) {
  auto vector = makeRowVector({makeFlatVector<bool>({false, true}), makeFlatVector<StringView>({"aa", "bb"})});

  uint8_t expectArr[] = {
      0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 24, 0, 0, 0, 97, 97, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 24, 0, 0, 0, 98, 98, 0, 0, 0, 0, 0, 0,
  };
  testRowBufferAddr(vector, expectArr, sizeof(expectArr));
}

TEST_F(VeloxColumnarToRowTest, Buffer_int64_int64_with_null) {
  auto vector = makeRowVector(
      {makeNullableFlatVector<int64_t>({std::nullopt, 2}), makeNullableFlatVector<int64_t>({std::nullopt, 2})});

  uint8_t expectArr[] = {
      3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
      0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
  };
  testRowBufferAddr(vector, expectArr, sizeof(expectArr));
}

} // namespace gluten