#include "usersimpl.h"
#include <Ice/Communicator.h>
#include <Ice/ObjectAdapter.h>
#include <icecube.h>
#include <modifycommand.h>
#include <notifications.h>
#include <sql/users/authenticate.sql.h>
#include <sql/users/create.sql.h>
#include <sql/users/find.sql.h>
#include <sql/users/get.sql.h>
#include <sql/users/getNew.sql.h>
#include <sql/users/mailshotsent.sql.h>
#include <sql/users/prune.sql.h>
#include <sql/users/safeDelete.sql.h>
#include <sql/users/track.sql.h>
#include <sql/users/tracked.sql.h>
#include <sql/users/untrack.sql.h>
#include <sql/users/verify.sql.h>

namespace Gentoo::Service {
	Users::Users(const DB::ConnectionPoolPtr & d) : IceTray::AbstractCachingDatabaseClient(d) { }

	Gentoo::UserPtr
	Users::authenticate(const std::string_view username, const std::string_view password, const Ice::Current &)
	{
		return fetchCache<Gentoo::UserPtr>(sql::users::authenticate, 30, username, password);
	}

	Gentoo::UserPtr
	Users::verify(const std::string_view username, const std::string_view verifyguid, const Ice::Current &)
	{
		return fetch<Gentoo::UserPtr>(sql::users::verify, username, verifyguid);
	}

	Gentoo::UserPtr
	Users::get(Ice::Int id, const Ice::Current &)
	{
		return fetch<Gentoo::UserPtr>(sql::users::get, id);
	}

	Gentoo::NewUserPtr
	Users::getNew(const std::string_view username, const std::string_view password, const Ice::Current &)
	{
		return fetch<Gentoo::NewUserPtr>(sql::users::getNew, username, password);
	}

	Gentoo::UserPtr
	Users::find(const std::string_view username, const Ice::Current &)
	{
		return fetch<Gentoo::UserPtr>(sql::users::find, username);
	}

	Gentoo::NewUserPtr
	Users::authOrCreate(const std::string_view & username, const std::string_view & password,
			const std::string_view & realname, const std::string_view & email)
	{
		auto existing = fetch<IceUtil::Optional<Gentoo::NewUserPtr>>(sql::users::getNew, username, password);
		if (existing && *existing) {
			return *existing;
		}
		return fetch<Gentoo::NewUserPtr>(sql::users::create, username, password, realname, email);
	}

	Gentoo::NewUserPtr
	Users::create(const std::string_view username, const std::string_view password, const std::string_view realname,
			const std::string_view email, const Ice::Current &)
	{
		auto notifications = IceTray::Cube::get<Notifications>();
		auto mailServer = IceTray::Cube::get<IceTray::Mail::MailServer>();

		auto dbc = db->get();
		DB::TransactionScope tx(*dbc.get());

		auto newUser = authOrCreate(username, password, realname, email);
		auto mail = notifications->getSignup(newUser);
		mailServer->sendEmail(mail);

		return newUser;
	}

	void
	Users::mailshotsent(Ice::Int id, const Ice::Current &)
	{
		auto dbc = db->get();
		auto upd = sql::users::mailshotsent.modify(dbc.get());
		upd->bindParamI(0, id);
		upd->execute();
	}

	void
	Users::remove(Ice::Int id, const std::string_view password, const Ice::Current &)
	{
		auto dbc = db->get();
		auto del = sql::users::safeDelete.modify(dbc.get());
		del->bindParamI(0, id);
		del->bindParamS(1, password);
		del->execute();
	}

	void
	Users::prune(const Ice::Current & current)
	{
		auto properties = current.adapter->getCommunicator()->getProperties();
		auto prunePeriod = properties->getPropertyWithDefault("GentooBrowseAPI.Users.PrunePeriod", "8 weeks");
		auto dbc = db->get();
		auto prune = sql::users::prune.modify(dbc.get());
		prune->bindParamS(0, prunePeriod);
		prune->execute();
	}

	void
	Users::track(Ice::Int userId, Ice::Int packageId, const Ice::Current &)
	{
		auto dbc = db->get();
		auto track = sql::users::track.modify(dbc.get());
		track->bindParamI(0, userId);
		track->bindParamI(1, packageId);
		track->execute();
	}

	void
	Users::untrack(Ice::Int userId, Ice::Int packageId, const Ice::Current &)
	{
		auto dbc = db->get();
		auto untrack = sql::users::untrack.modify(dbc.get());
		untrack->bindParamI(0, userId);
		untrack->bindParamI(1, packageId);
		untrack->execute();
	}

	Gentoo::PackageIds
	Users::tracked(Ice::Int userId, const Ice::Current &)
	{
		return fetchCache<Gentoo::PackageIds>(sql::users::tracked, 10, userId);
	}
}