#include <catch2/catch.hpp>

#include <language/ast/ASTNode.hpp>
#include <language/ast/ASTNodeArraySubscriptExpressionBuilder.hpp>
#include <language/node_processor/ArraySubscriptProcessor.hpp>

#include <pegtl/string_input.hpp>

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

TEST_CASE("ASTNodeArraySubscriptExpressionBuilder", "[language]")
{
  SECTION("R^d component access")
  {
    std::unique_ptr node = std::make_unique<ASTNode>();

    SECTION("R^1")
    {
      {
        std::unique_ptr array_node = std::make_unique<ASTNode>();
        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 1};
        node->emplace_back(std::move(array_node));
      }
      REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node});
      REQUIRE(bool{node->m_node_processor});
      auto& node_processor = *node->m_node_processor;
      REQUIRE(typeid(node_processor).name() == typeid(ArraySubscriptProcessor<TinyVector<1>>).name());
    }

    SECTION("R^2")
    {
      {
        std::unique_ptr array_node = std::make_unique<ASTNode>();
        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 2};
        node->emplace_back(std::move(array_node));
      }
      REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node});
      REQUIRE(bool{node->m_node_processor});
      auto& node_processor = *node->m_node_processor;
      REQUIRE(typeid(node_processor).name() == typeid(ArraySubscriptProcessor<TinyVector<2>>).name());
    }

    SECTION("R^3")
    {
      {
        std::unique_ptr array_node = std::make_unique<ASTNode>();
        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 3};
        node->emplace_back(std::move(array_node));
      }
      REQUIRE_NOTHROW(ASTNodeArraySubscriptExpressionBuilder{*node});
      REQUIRE(bool{node->m_node_processor});
      auto& node_processor = *node->m_node_processor;
      REQUIRE(typeid(node_processor).name() == typeid(ArraySubscriptProcessor<TinyVector<3>>).name());
    }
  }

  SECTION("R^d component bad access")
  {
    std::unique_ptr node = std::make_unique<ASTNode>();

    SECTION("R^d (d < 1)")
    {
      {
        std::unique_ptr array_node = std::make_unique<ASTNode>();
        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 0};
        node->emplace_back(std::move(array_node));
      }
      REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array dimension");
    }
    SECTION("R^d (d > 3)")
    {
      {
        std::unique_ptr array_node = std::make_unique<ASTNode>();
        array_node->m_data_type    = ASTNodeDataType{ASTNodeDataType::vector_t, 4};
        node->emplace_back(std::move(array_node));
      }
      REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array dimension");
    }
  }

  SECTION("invalid array expression")
  {
    std::unique_ptr node = std::make_unique<ASTNode>();
    {
      std::unique_ptr array_node = std::make_unique<ASTNode>();
      node->emplace_back(std::move(array_node));
    }
    REQUIRE_THROWS_WITH(ASTNodeArraySubscriptExpressionBuilder{*node}, "unexpected error: invalid array type");
  }
}