#include <gmock/gmock.h>

#include "mocks/SessionMock.hpp"
#include "mocks/widgets/AuthPageMock.hpp"
#include "mocks/widgets/MainPageMock.hpp"
#include "utils/UniquePtrMockWrapper.hpp"

#include <Wt/Test/WTestEnvironment>

#include <eedb/EEDB.hpp>
#include <eedb/Session.hpp>
#include <eedb/db/connection.hpp>
#include <eedb/widgets/Theme.hpp>

class AuthPageFactory {
  public:
    MOCK_METHOD0(impl, std::unique_ptr< eedb::AuthPage >());
    auto operator()() {
        return impl();
    }
};

class HomePageFactory {
  public:
    MOCK_METHOD0(impl, std::unique_ptr< eedb::HomePage >());
    auto operator()() {
        return impl();
    }
};

using namespace testing;

class EedbApplicationTest : public Test {
  public:
    EedbApplicationTest() {
        createApp();
    }

    void createApp() {
        expectCreateAuthPage();

        auto session = std::make_unique< eedb::SessionMock >();
        EXPECT_CALL(*session, enviroment()).WillOnce(ReturnRef(env));

        sut = new eedb::EEDB(std::move(session), [this]() { return authPageFactory(); }, [this]() { return homePageFactory(); });
    }
    void expectCreateAuthPage() {
        EXPECT_CALL(authPageFactory, impl()).WillOnce(Return(ByMove(authPage.getPtr())));

        EXPECT_CALL(*authPage, registerNeedVerification(_)).WillOnce(SaveArg< 0 >(&callbacks[0]));
        EXPECT_CALL(*authPage, registerOnUserWeakLogin(_)).WillOnce(SaveArg< 0 >(&callbacks[1]));
        EXPECT_CALL(*authPage, registerOnUserStrongLogin(_)).WillOnce(SaveArg< 0 >(&callbacks[2]));
        EXPECT_CALL(*authPage, registerOnUserLogout(_)).WillOnce(SaveArg< 0 >(&callbacks[3]));
        EXPECT_CALL(*authPage, attachTo(Ne(nullptr)));
        EXPECT_CALL(*authPage, processEnvironment());
    }

    void expectCreateHomePage() {
        EXPECT_CALL(homePageFactory, impl()).WillOnce(Return(ByMove(homePage.getPtr())));
        EXPECT_CALL(*authPage, detach());
        EXPECT_CALL(*homePage, attachTo(_));
    }

  protected:
    Wt::Test::WTestEnvironment env;

    std::array< std::function< void() >, 4 > callbacks;

    UniquePtrMockWrapper< eedb::AuthPageMock > authPage;
    AuthPageFactory authPageFactory;

    UniquePtrMockWrapper< eedb::HomePageMock > homePage;
    HomePageFactory homePageFactory;

    eedb::EEDB * sut;
};

TEST_F(EedbApplicationTest, createApp) {}

TEST_F(EedbApplicationTest, strongLoginCreatesMainPage) {
    expectCreateHomePage();
    callbacks[2]();
}

TEST_F(EedbApplicationTest, weakLoginCreatesMainPage) {
    expectCreateHomePage();
    callbacks[1]();
}
