package tc.oc.pgm.tnt.license;
import java.time.Instant;
import java.util.Collections;
import java.util.List;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Singleton;
import net.md_5.bungee.api.ChatColor;
import net.md_5.bungee.api.chat.TranslatableComponent;
import org.bukkit.event.EventBus;
import tc.oc.api.bukkit.users.OnlinePlayers;
import tc.oc.api.docs.User;
import tc.oc.api.docs.UserId;
import tc.oc.api.docs.virtual.UserDoc;
import tc.oc.api.docs.virtual.UserDoc.License.Grant;
import tc.oc.api.docs.virtual.UserDoc.License.Request;
import tc.oc.api.docs.virtual.UserDoc.License.Stats;
import tc.oc.api.users.UserService;
import tc.oc.commons.bukkit.chat.Audiences;
import tc.oc.commons.bukkit.chat.WarningComponent;
import tc.oc.minecraft.scheduler.MainThreadExecutor;
import tc.oc.commons.core.chat.Audience;
import tc.oc.commons.core.chat.Component;
import tc.oc.commons.core.logging.Loggers;
import tc.oc.commons.core.plugin.PluginFacet;
import tc.oc.pgm.match.MatchFinder;
/**
* Handles granting and revoking TNT licenses.
*/
@Singleton
public class LicenseBroker implements PluginFacet {
private final Logger logger;
private final MainThreadExecutor executor;
private final UserService userService;
private final OnlinePlayers onlinePlayers;
private final Audiences audiences;
private final EventBus eventBus;
private final MatchFinder matchPlayers;
@Inject LicenseBroker(Loggers loggers, MainThreadExecutor executor, UserService userService, OnlinePlayers onlinePlayers, Audiences audiences, EventBus eventBus, MatchFinder matchPlayers) {
this.logger = loggers.get(getClass());
this.executor = executor;
this.userService = userService;
this.onlinePlayers = onlinePlayers;
this.audiences = audiences;
this.eventBus = eventBus;
this.matchPlayers = matchPlayers;
}
/**
* Display information about a player's TNT license.
*/
public void information(User user, Audience audience) {
if(user.hasTntLicense()) {
audience.sendMessage(new Component(
new TranslatableComponent("tnt.license.info.alreadyHas", "/tnt revoke"),
ChatColor.YELLOW
));
} else if(user.requested_tnt_license_at() != null) {
audience.sendMessage(new Component(
new TranslatableComponent("tnt.license.request.alreadyHas"),
ChatColor.YELLOW
));
} else {
audience.sendMessage(new Component(
new TranslatableComponent("tnt.license.info.doesNotHave", "/tnt request"),
ChatColor.YELLOW
));
}
}
/**
* Request for a player to receive a TNT license.
*/
public void request(User user, Audience audience) {
if(user.requestedTntLicense()) {
audience.sendMessage(new WarningComponent("tnt.license.request.alreadyHas"));
} else {
executor.callback(
userService.update(user, new RequestLicense()),
result -> {
logger.info(result.username() + " requested a TNT license");
audience.sendMessage(
new Component(new TranslatableComponent("tnt.license.request.success"),
ChatColor.YELLOW)
);
}
);
}
}
public enum GrantReason {
ENEMY_KILLS, OBJECTIVES;
}
/**
* Grants a player a TNT license.
*/
public void grant(User user, GrantReason reason) {
if(!user.hasTntLicense()) {
executor.callback(userService.update(user, new GrantLicense()), user1 -> {
logger.info(user.username() + " was granted a TNT license for " + reason);
onlinePlayers.byUserId(user).ifPresent(player -> audiences.get(player).sendMessage(
new Component(
new TranslatableComponent(
"tnt.license.grant.success",
new TranslatableComponent("tnt.license.grant.reason." + reason.name().toLowerCase())
), ChatColor.YELLOW
)
));
});
}
}
public void grant(UserId userId, GrantReason reason) {
executor.callback(userService.find(userId), user -> grant(user, reason));
}
public enum RevokeReason {
TEAM_KILLS, COMMAND;
}
/**
* Revoke a TNT license from a player.
*/
public void revoke(User user, RevokeReason reason, boolean auto) {
final Audience audience = audiences.get(onlinePlayers.find(user));
final boolean hadLicense = user.hasTntLicense();
if(!(hadLicense || user.requestedTntLicense())) {
if(!auto) {
audience.sendMessage(new WarningComponent("tnt.license.revoke.hasNotRequested"));
}
return;
}
executor.callback(
userService.update(
user,
auto ? new RevokeLicense() : new CancelLicense() // Manual revoke cancels the request as well, auto-revoke does not
),
user1 -> {
if(hadLicense) {
logger.info(user.username() + " lost a TNT license for " + reason + (auto ? " automatically" : " manually"));
audience.sendMessage(new Component(
new TranslatableComponent(
"tnt.license.revoke.success",
new TranslatableComponent("tnt.license.revoke.reason." + reason.name().toLowerCase())
), ChatColor.YELLOW
));
} else if(!auto) {
audience.sendMessage(new WarningComponent("tnt.license.revoke.cancelled"));
}
matchPlayers.player(user).ifPresent(
player -> eventBus.callEvent(new LicenseRevokeEvent(player, hadLicense))
);
}
);
}
private static class ResetStats implements Stats {
@Override
public List<UserDoc.License.Kill> tnt_license_kills() {
return Collections.emptyList();
}
}
private static class RequestLicense extends ResetStats implements Request {
@Override
public Instant requested_tnt_license_at() {
return Instant.now();
}
}
private static class GrantLicense extends ResetStats implements Grant {
@Override
public Instant granted_tnt_license_at() {
return Instant.now();
}
}
private static class RevokeLicense extends ResetStats implements Grant {
@Override
public @Nullable Instant granted_tnt_license_at() {
return null;
}
}
private static class CancelLicense extends RevokeLicense implements Request {
@Override
public @Nullable Instant requested_tnt_license_at() {
return null;
}
}
}