/*
* Author:          Patrick-Christopher Mattulat
* Co-Author:       Claude Sonnet 4.6 (LLM)
* Company:         Lynar Studios
* E-Mail:          webmaster@lynarstudios.com
* Created:         2024-05-16
* Changed:         2026-06-23
*
* */

#include <gtest/gtest.h>
#include <ls-std-event-test.hpp>
#include <ls-std/ls-std-core.hpp>
#include <ls-std/ls-std-event.hpp>
#include <memory>

using ls::standard::core::NullPointerException;
using ls::standard::event::EventListener;
using ls::standard::event::EventManager;
using ::std::make_shared;
using ::std::string;
using test::event::Button;
using test::event::OnClickEvent;
using testing::Test;

namespace
{
  class EventListenerTest : public Test
  {
    public:

      EventListenerTest() = default;
      ~EventListenerTest() override = default;
  };

  TEST_F(EventListenerTest, getClassName)
  {
    ASSERT_STREQ("EventListener", EventListener().getClassName().c_str());
  }

  TEST_F(EventListenerTest, getId)
  {
    ASSERT_EQ(0, EventListener().getId());
  }

  TEST_F(EventListenerTest, setId)
  {
    auto listener = EventListener();

    ASSERT_EQ(0, listener.getId());
    listener.setId(17);
    ASSERT_EQ(17, listener.getId());
  }

  TEST_F(EventListenerTest, subscribe_with_missing_event_manager)
  {
    auto myButton = make_shared<Button>();

    EXPECT_THROW(
        {
          try
          {
            myButton->subscribe(OnClickEvent(), [myButton]() mutable { myButton->onClickEvent(); });
          }
          catch (const NullPointerException &_exception)
          {
            const string actual = _exception.what();
            const string expected = _exception.getName() + " thrown - no event manager is provided for OnClickEvent";

            EXPECT_STREQ(expected.c_str(), actual.c_str());
            throw;
          }
        },
        NullPointerException);
  }

  TEST_F(EventListenerTest, subscribe)
  {
    auto myButton = make_shared<Button>();
    ASSERT_TRUE(myButton->subscribe(OnClickEvent().supervisedBy(make_shared<EventManager>()), [myButton]() mutable { myButton->onClickEvent(); }));
  }

  TEST_F(EventListenerTest, subscribe_second_time)
  {
    auto myButton = make_shared<Button>();
    const auto eventManager = make_shared<EventManager>();

    ASSERT_TRUE(myButton->subscribe(OnClickEvent().supervisedBy(eventManager), [myButton]() mutable { myButton->onClickEvent(); }));
    ASSERT_FALSE(myButton->subscribe(OnClickEvent().supervisedBy(eventManager), [myButton]() mutable { myButton->onClickEvent(); }));
  }

  TEST_F(EventListenerTest, unsubscribe_with_missing_event_manager)
  {
    const auto myButton = make_shared<Button>();

    EXPECT_THROW(
        {
          try
          {
            myButton->unsubscribe(OnClickEvent());
          }
          catch (const NullPointerException &_exception)
          {
            const string actual = _exception.what();
            const string expected = _exception.getName() + " thrown - no event manager is provided for OnClickEvent";

            EXPECT_STREQ(expected.c_str(), actual.c_str());
            throw;
          }
        },
        NullPointerException);
  }

  TEST_F(EventListenerTest, unsubscribe)
  {
    auto myButton = make_shared<Button>();
    const auto eventManager = make_shared<EventManager>();

    ASSERT_TRUE(myButton->subscribe(OnClickEvent().supervisedBy(eventManager), [myButton]() mutable { myButton->onClickEvent(); }));
    ASSERT_TRUE(myButton->unsubscribe(OnClickEvent().supervisedBy(eventManager)));
  }

  TEST_F(EventListenerTest, unsubscribe_second_time)
  {
    auto myButton = make_shared<Button>();
    const auto eventManager = make_shared<EventManager>();

    ASSERT_TRUE(myButton->subscribe(OnClickEvent().supervisedBy(eventManager), [myButton]() mutable { myButton->onClickEvent(); }));
    ASSERT_TRUE(myButton->unsubscribe(OnClickEvent().supervisedBy(eventManager)));
    ASSERT_FALSE(myButton->unsubscribe(OnClickEvent().supervisedBy(eventManager)));
  }
}
