package com.nincraft.ninbot.components.twitch;

import com.nincraft.ninbot.components.common.LocaleService;
import com.nincraft.ninbot.components.config.ConfigConstants;
import com.nincraft.ninbot.components.config.ConfigService;
import lombok.extern.log4j.Log4j2;
import lombok.val;
import net.dv8tion.jda.core.entities.Game;
import net.dv8tion.jda.core.entities.Guild;
import net.dv8tion.jda.core.entities.Member;
import net.dv8tion.jda.core.events.user.update.GenericUserPresenceEvent;
import net.dv8tion.jda.core.events.user.update.UserUpdateGameEvent;
import net.dv8tion.jda.core.hooks.ListenerAdapter;
import org.springframework.stereotype.Component;

import java.util.ResourceBundle;

@Component
@Log4j2
public class TwitchListener extends ListenerAdapter {

    private ConfigService configService;
    private LocaleService localeService;

    public TwitchListener(ConfigService configService, LocaleService localeService) {
        this.configService = configService;
        this.localeService = localeService;
    }

    @Override
    public void onGenericUserPresence(GenericUserPresenceEvent event) {
        if (event instanceof UserUpdateGameEvent) {
            val updateGameEvent = (UserUpdateGameEvent) event;
            log.debug("User Presence Updated: User {}, Old game {}, New game {}", updateGameEvent.getUser(), updateGameEvent.getOldGame(), updateGameEvent.getNewGame());
            if (updateGameEvent.getNewGame() != null) {
                log.debug("New game URL {}", updateGameEvent.getNewGame().getUrl());
            }
            if (isNowStreaming(updateGameEvent)) {
                val serverId = event.getGuild().getId();
                val streamingAnnounceUsers = configService.getValuesByName(serverId, ConfigConstants.STREAMING_ANNOUNCE_USERS);
                if (streamingAnnounceUsers.contains(updateGameEvent.getUser().getId())) {
                    announceStream(updateGameEvent, serverId);
                }
            } else if (isNoLongerStreaming(updateGameEvent)) {
                removeRole(updateGameEvent.getGuild(), updateGameEvent.getMember());
            }
        }
    }

    private void removeRole(Guild guild, Member member) {
        val streamingRoleId = configService.getSingleValueByName(guild.getId(), ConfigConstants.STREAMING_ROLE);
        streamingRoleId.ifPresent(roleId -> {
            val streamingRole = guild.getRoleById(roleId);
            guild.getController().removeSingleRoleFromMember(member, streamingRole).queue();
        });
    }

    private boolean isNoLongerStreaming(UserUpdateGameEvent updateGameEvent) {
        return checkStreaming(updateGameEvent.getNewGame(), updateGameEvent.getOldGame());
    }

    private boolean isNowStreaming(UserUpdateGameEvent updateGameEvent) {
        return checkStreaming(updateGameEvent.getOldGame(), updateGameEvent.getNewGame());
    }

    private boolean checkStreaming(Game previousGame, Game nextGame) {
        return (previousGame == null || previousGame.getUrl() == null) && nextGame != null && nextGame.getUrl() != null;
    }

    private void announceStream(UserUpdateGameEvent updateGameEvent, String serverId) {
        val streamingAnnounceChannel = configService.getSingleValueByName(serverId, ConfigConstants.STREAMING_ANNOUNCE_CHANNEL);
        streamingAnnounceChannel.ifPresent(streamingAnnounceChannelString -> {
            val guild = updateGameEvent.getGuild();
            val channel = guild.getTextChannelById(streamingAnnounceChannelString);
            val user = updateGameEvent.getUser().getName();
            val url = updateGameEvent.getNewGame().getUrl();
            addRole(guild, guild.getMember(updateGameEvent.getUser()));
            ResourceBundle resourceBundle = ResourceBundle.getBundle("lang", localeService.getLocale(serverId));
            channel.sendMessage(String.format(resourceBundle.getString("listener.twitch.announce"), user, url)).queue();
        });
    }

    private void addRole(Guild guild, Member member) {
        val streamingRoleId = configService.getSingleValueByName(guild.getId(), ConfigConstants.STREAMING_ROLE);
        streamingRoleId.ifPresent(roleId -> {
            val streamingRole = guild.getRoleById(roleId);
            guild.getController().addSingleRoleToMember(member, streamingRole).queue();
        });
    }
}

@@ -667,27 +667,78 @@
 ava.
-u
 ti
-l.ResourceBundle
+me.Instant;%0Aimport java.time.temporal.ChronoUnit;%0Aimport java.util.*
 ;%0A%0A@
@@ -891,16 +891,55 @@
 Service;
+%0A    private List%3CString%3E cooldownList;
 %0A%0A    pu
@@ -1102,24 +1102,71 @@
 aleService;%0A
+        this.cooldownList = new ArrayList%3C%3E();%0A
     %7D%0A%0A    @
@@ -1702,48 +1702,109 @@
     
-if (isNowStreaming(updateGameEvent)) %7B%0A 
+val serverId = event.getGuild().getId();%0A            val userId = updateGameEvent.getUser().getId();%0A
     
@@ -1815,51 +1815,105 @@
     
-   val
+String
  server
+User
 Id = 
-event.getGuild().getId();
+serverId + %22-%22 + userId;%0A            if (isNowStreaming(updateGameEvent)) %7B
 %0A   
@@ -2061,138 +2061,383 @@
 if (
-streamingAnnounceUsers.contains(updateGameEvent.getUser().getId())) %7B%0A                    announceStream(updateGameEvent, serverId
+!cooldownList.contains(serverUserId) && streamingAnnounceUsers.contains(userId)) %7B%0A                    Timer timer = new Timer();%0A                    announceStream(updateGameEvent, serverId);%0A                    cooldownList.add(serverUserId);%0A                    timer.schedule(new TwitchAnnounceCooldown(serverUserId), Date.from(Instant.now().plus(30, ChronoUnit.MINUTES))
 );%0A 
@@ -2597,24 +2597,75 @@
 tMember());%0A
+                cooldownList.remove(serverUserId);%0A
             
@@ -4876,10 +4876,322 @@
 ;%0A    %7D%0A
-%7D
 %0A
+    class TwitchAnnounceCooldown extends TimerTask %7B%0A%0A        private String serverUserId;%0A%0A        TwitchAnnounceCooldown(String serverUserId) %7B%0A            this.serverUserId = serverUserId;%0A        %7D%0A%0A        @Override%0A        public void run() %7B%0A            cooldownList.remove(serverUserId);%0A        %7D%0A    %7D%0A%7D

Add cooldown timer for Twitch announcements