/*
 *
 * This file is a part of the CaosDB 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 "caosdb/entity.h"                       // for Entity, Parent, Par...
#include "caosdb/entity/v1alpha1/main.grpc.pb.h" // for EntityTransactionSe...
#include "caosdb/entity/v1alpha1/main.pb.h"      // for IdResponse, Message
#include "caosdb/message_code.h"                 // for MessageCode
#include "caosdb/transaction.h"                  // for Transaction
#include "gtest/gtest-message.h"                 // for Message
#include "gtest/gtest-test-part.h"               // for TestPartResult, Sui...
#include "gtest/gtest_pred_impl.h"               // for Test, EXPECT_EQ
#include <iostream>                              // for endl, basic_ostream
#include <memory>                                // for allocator, shared_ptr
#include <string>                                // for operator<<

namespace caosdb::entity {
using caosdb::entity::v1alpha1::IdResponse;

TEST(test_entity, test_parent_setters) {
  auto parent = Parent();
  parent.SetName("RT1");
  parent.SetId("some-id");

  EXPECT_EQ(parent.GetName(), "RT1");
  EXPECT_EQ(parent.GetId(), "some-id");
}

TEST(test_entity, test_append_parent) {
  auto parent = Parent();
  parent.SetId("some-id");

  auto entity = Entity();
  EXPECT_EQ(entity.GetParents().Size(), 0);
  entity.AppendParent(parent);
  EXPECT_EQ(entity.GetParents().Size(), 1);

  auto same_parent = entity.GetParents().At(0);
  EXPECT_EQ(same_parent.GetId(), "some-id");
}

TEST(test_entity, test_insert_entity) {
  auto transaction = caosdb::transaction::Transaction(
    std::shared_ptr<transaction::EntityTransactionService::Stub>(nullptr));

  auto entity = Entity();
  entity.SetId("entity_id");
  entity.SetVersionId("version_id");

  EXPECT_EQ(entity.GetId(), "entity_id");
  EXPECT_EQ(entity.GetVersionId(), "version_id");

  transaction.InsertEntity(&entity);

  EXPECT_EQ(entity.GetId(), "entity_id");
  EXPECT_EQ(entity.GetVersionId(), "version_id");
}

// TODO(fspreck) cognitive complexity > 25 (threshold)
TEST(test_entity, test_insert_with_role) { // NOLINT
  auto transaction = caosdb::transaction::Transaction(
    std::shared_ptr<transaction::EntityTransactionService::Stub>(nullptr));

  auto entity = Entity();
  entity.SetId("entity_id");
  entity.SetVersionId("version_id");
  entity.SetRole("Property");
  entity.SetDatatype("DOUBLE");
  entity.SetName("Length");
  entity.SetUnit("m");
  entity.SetValue("5.5");

  transaction.InsertEntity(&entity);

  EXPECT_EQ(entity.GetId(), "entity_id");
  EXPECT_EQ(entity.GetVersionId(), "version_id");
  EXPECT_EQ(entity.GetRole(), "Property");
  EXPECT_EQ(entity.GetDatatype(), "DOUBLE");
  EXPECT_EQ(entity.GetName(), "Length");
  EXPECT_EQ(entity.GetUnit(), "m");
  EXPECT_EQ(entity.GetValue(), "5.5");
}

TEST(test_entity, test_insert_with_parent) {
  auto transaction = caosdb::transaction::Transaction(
    std::shared_ptr<transaction::EntityTransactionService::Stub>(nullptr));

  auto entity = Entity();
  entity.SetId("entity_id");

  auto parent = Parent();
  parent.SetId("parent_id");
  parent.SetName("parent_name");
  EXPECT_EQ(parent.GetId(), "parent_id");
  EXPECT_EQ(parent.GetName(), "parent_name");

  entity.AppendParent(parent);

  transaction.InsertEntity(&entity);

  std::cout << entity.ToString() << std::endl;
  EXPECT_EQ(entity.GetId(), "entity_id");
  EXPECT_EQ(entity.GetParents().Size(), 1);
  auto inserted_parent = entity.GetParents().At(0);
  EXPECT_EQ(inserted_parent.GetId(), parent.GetId());
  EXPECT_EQ(inserted_parent.GetName(), parent.GetName());
}

// TODO(tf) cognitive complexity > 25 (threshold)
TEST(test_entity, test_from_id_response) { // NOLINT
  IdResponse idResponse;
  idResponse.set_id("entity_id");
  auto *error = idResponse.add_entity_errors();
  error->set_code(MessageCode::ENTITY_DOES_NOT_EXIST);
  error->set_description("error_desc");

  Entity entity(&idResponse);

  std::cout << entity.ToString() << std::endl;
  EXPECT_EQ(entity.GetId(), "entity_id");
  EXPECT_TRUE(entity.HasErrors());
  EXPECT_EQ(entity.GetErrors().Size(), 1);
  EXPECT_EQ(entity.GetErrors().At(0).GetDescription(), "error_desc");
  EXPECT_EQ(entity.GetErrors().At(0).GetCode(),
            MessageCode::ENTITY_DOES_NOT_EXIST);

  IdResponse idr_warnings_and_infos;
  idr_warnings_and_infos.set_id("other_entity_id");
  auto *warning = idr_warnings_and_infos.add_entity_warnings();
  warning->set_description("warning_desc");
  warning->set_code(MessageCode::ENTITY_HAS_NO_PROPERTIES);
  auto *info = idr_warnings_and_infos.add_entity_infos();
  info->set_description("info_desc");
  info->set_code(MessageCode::UNSPECIFIED);

  Entity other_ent(&idr_warnings_and_infos);

  EXPECT_EQ(other_ent.GetId(), "other_entity_id");
  EXPECT_EQ(other_ent.GetWarnings().Size(), 1);
  EXPECT_TRUE(other_ent.HasWarnings());
  EXPECT_EQ(other_ent.GetWarnings().At(0).GetDescription(), "warning_desc");
  EXPECT_EQ(other_ent.GetWarnings().At(0).GetCode(),
            MessageCode::ENTITY_HAS_NO_PROPERTIES);
  EXPECT_EQ(other_ent.GetInfos().Size(), 1);
  EXPECT_EQ(other_ent.GetInfos().At(0).GetDescription(), "info_desc");
  EXPECT_EQ(other_ent.GetInfos().At(0).GetCode(), MessageCode::UNSPECIFIED);
}

} // namespace caosdb::entity