#include <eedb/EEDB.hpp>
#include <eedb/Session.hpp>

#include <eedb/auth/PgUserAuth.hpp>
#include <eedb/auth/Services.hpp>

#include <eedb/db/config.hpp>
#include <eedb/db/connection.hpp>

#include <eedb/widgets/DefaultAuthPage.hpp>
#include <eedb/widgets/DefaultHomePage.hpp>
#include <eedb/widgets/DefaultNavigationBar.hpp>

#include <Wt/WApplication>
#include <Wt/WServer>

Wt::WApplication * createApplication(const Wt::WEnvironment & env) {
    using std::move;
    using std::make_unique;
    using std::unique_ptr;

    auto dbConfig     = make_unique< eedb::db::PgConfig >(env);
    auto dbConnection = make_unique< eedb::db::PgConnection >(move(dbConfig));
    auto session      = unique_ptr< eedb::Session >(make_unique< eedb::WebSession >(move(dbConnection), env));

    auto authPageFactory = [_session = session.get()]()->std::unique_ptr< eedb::AuthPage > {
        auto userDatabase = make_unique< eedb::auth::PgUserAuth >(_session->db(), _session->enviroment());
        auto services     = eedb::auth::Services();
        auto & login      = _session->login();

        return make_unique< eedb::DefaultAuthPage >(services, std::move(userDatabase), login);
    };

    auto homePageFactory = [_session = session.get()]()->std::unique_ptr< eedb::HomePage > {
        auto navigationBar = std::make_unique< eedb::DefaultNavigationBar >();
        return make_unique< eedb::DefaultHomePage >(*_session, std::move(navigationBar));
    };

    return new eedb::EEDB{std::move(session), authPageFactory, homePageFactory};
}

int main(int argc, char ** argv) {
    try {
        Wt::WServer server(argc, argv, WTHTTP_CONFIGURATION);
        server.addEntryPoint(Wt::Application, createApplication);
        eedb::auth::Services::configureAuth();
        server.run();
    } catch(Wt::WServer::Exception & e) {
        std::cerr << e.what() << std::endl;
    } catch(std::exception & e) {
        std::cerr << "exception: " << e.what() << std::endl;
    }
}
