/*
 * This file is a part of the LinkAhead Project.
 *
 * Copyright (C) 2021 Timm Fitschen <t.fitschen@indiscale.com>
 * Copyright (C) 2021 IndiScale GmbH <info@indiscale.com>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as
 * published by the Free Software Foundation, either version 3 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
 *
 */
#include "linkahead/connection.h"         // for Connection, ConnectionManager
#include "linkahead/data_type.h"          // for AtomicDataType, AtomicDataTyp...
#include "linkahead/entity.h"             // for Entity, Properties, Property
#include "linkahead/transaction.h"        // for Transaction, ResultSet, Resul...
#include "linkahead/transaction_status.h" // for TransactionStatus
#include <gtest/gtest-message.h>          // for Message
#include <gtest/gtest-test-part.h>        // for TestPartResult, SuiteApiResolver
#include <gtest/gtest_pred_impl.h>        // for AssertionResult, EXPECT_EQ
#include <memory>                         // for unique_ptr, allocator, __shar...

namespace linkahead::entity {

class test_properties : public ::testing::Test {
protected:
  void SetUp() override { DeleteEntities(); }

  void TearDown() override { DeleteEntities(); }

  static void DeleteEntities() {
    const auto &connection = linkahead::connection::ConnectionManager::GetDefaultConnection();
    auto query_transaction(connection->CreateTransaction());
    query_transaction->Query("FIND ENTITY WITH id > 99");
    query_transaction->Execute();
    if (query_transaction->GetResultSet().size() > 0) {
      auto delete_transaction(connection->CreateTransaction());
      for (const Entity &entity : query_transaction->GetResultSet()) {
        delete_transaction->DeleteById(entity.GetId());
      }
      delete_transaction->Execute();
    }
  }
};

TEST_F(test_properties, retrieve_unit) {
  const auto &connection = linkahead::connection::ConnectionManager::GetDefaultConnection();

  auto insertion_prop(connection->CreateTransaction());

  Entity abstract_property;
  abstract_property.SetRole(Role::PROPERTY);
  abstract_property.SetName("TestProp");
  abstract_property.SetDataType(AtomicDataType::DOUBLE);
  abstract_property.SetUnit("V");

  insertion_prop->InsertEntity(&abstract_property);
  insertion_prop->Execute();
  EXPECT_TRUE(insertion_prop->GetStatus().IsTerminated());

  auto insertion_rt(connection->CreateTransaction());

  Property property;
  property.SetId(insertion_prop->GetResultSet().at(0).GetId());

  Entity entity;
  entity.SetRole(Role::RECORD_TYPE);
  entity.SetName("TestRT");
  entity.AppendProperty(property);

  insertion_rt->InsertEntity(&entity);
  insertion_rt->Execute();
  EXPECT_TRUE(insertion_rt->GetStatus().IsTerminated());
  EXPECT_FALSE(insertion_rt->GetStatus().IsError());

  // retrieve and check again
  auto retrieval(connection->CreateTransaction());
  retrieval->RetrieveById(insertion_prop->GetResultSet().at(0).GetId());
  retrieval->RetrieveById(insertion_rt->GetResultSet().at(0).GetId());
  retrieval->ExecuteAsynchronously();
  retrieval->WaitForIt();

  EXPECT_TRUE(retrieval->GetStatus().IsTerminated());
  EXPECT_FALSE(retrieval->GetStatus().IsError());

  const auto &same_property = retrieval->GetResultSet().at(0);
  EXPECT_EQ(same_property.GetDataType().GetAsAtomic(), AtomicDataType::DOUBLE);
  EXPECT_EQ(same_property.GetUnit(), "V");

  const auto &same_record_type = retrieval->GetResultSet().at(1);
  EXPECT_EQ(same_record_type.GetProperties().at(0).GetDataType().GetAsAtomic(),
            AtomicDataType::DOUBLE);
  EXPECT_EQ(same_record_type.GetProperties().at(0).GetUnit(), "V");
}

} // namespace linkahead::entity