#include <catch2/catch_test_macros.hpp>
#include <catch2/matchers/catch_matchers_all.hpp>

#include <MeshDataBaseForTests.hpp>
#include <mesh/Mesh.hpp>
#include <mesh/MeshVariant.hpp>

// clazy:excludeall=non-pod-global-static

TEST_CASE("MeshVariant", "[mesh]")
{
  SECTION("1D")
  {
    auto mesh_v = MeshDataBaseForTests::get().unordered1DMesh();
    auto mesh   = mesh_v->get<Mesh<1>>();

    const std::string error_msg =
      R"(error: invalid mesh type type
- required Mesh<3ul>
- contains Mesh<1ul>)";

    REQUIRE_THROWS_WITH(mesh_v->get<Mesh<3>>(), error_msg);

    REQUIRE(mesh->id() == mesh_v->id());
    REQUIRE(mesh->numberOfCells() == mesh_v->numberOfCells());
    REQUIRE(mesh->numberOfFaces() == mesh_v->numberOfFaces());
    REQUIRE(mesh->numberOfEdges() == mesh_v->numberOfEdges());
    REQUIRE(mesh->numberOfNodes() == mesh_v->numberOfNodes());

    {
      std::ostringstream os_v;
      os_v << *mesh_v;

      std::ostringstream os;
      os << *mesh;

      REQUIRE(os_v.str() == os.str());
    }
  }

  SECTION("2D")
  {
    auto mesh_v = MeshDataBaseForTests::get().hybrid2DMesh();
    auto mesh   = mesh_v->get<Mesh<2>>();

    const std::string error_msg =
      R"(error: invalid mesh type type
- required Mesh<1ul>
- contains Mesh<2ul>)";

    REQUIRE_THROWS_WITH(mesh_v->get<Mesh<1>>(), error_msg);

    REQUIRE(mesh->id() == mesh_v->id());
    REQUIRE(mesh->numberOfCells() == mesh_v->numberOfCells());
    REQUIRE(mesh->numberOfFaces() == mesh_v->numberOfFaces());
    REQUIRE(mesh->numberOfEdges() == mesh_v->numberOfEdges());
    REQUIRE(mesh->numberOfNodes() == mesh_v->numberOfNodes());

    {
      std::ostringstream os_v;
      os_v << *mesh_v;

      std::ostringstream os;
      os << *mesh;

      REQUIRE(os_v.str() == os.str());
    }
  }

  SECTION("3D")
  {
    auto mesh_v = MeshDataBaseForTests::get().hybrid3DMesh();
    auto mesh   = mesh_v->get<Mesh<3>>();

    const std::string error_msg =
      R"(error: invalid mesh type type
- required Mesh<2ul>
- contains Mesh<3ul>)";

    REQUIRE_THROWS_WITH(mesh_v->get<Mesh<2>>(), error_msg);

    REQUIRE(mesh->id() == mesh_v->id());
    REQUIRE(mesh->numberOfCells() == mesh_v->numberOfCells());
    REQUIRE(mesh->numberOfFaces() == mesh_v->numberOfFaces());
    REQUIRE(mesh->numberOfEdges() == mesh_v->numberOfEdges());
    REQUIRE(mesh->numberOfNodes() == mesh_v->numberOfNodes());

    {
      std::ostringstream os_v;
      os_v << *mesh_v;

      std::ostringstream os;
      os << *mesh;

      REQUIRE(os_v.str() == os.str());
    }
  }
}