package com.nincraft.ninbot.components.twitch;

import com.nincraft.ninbot.components.common.LocaleService;
import com.nincraft.ninbot.components.common.MessageBuilderHelper;
import com.nincraft.ninbot.components.config.ConfigConstants;
import com.nincraft.ninbot.components.config.ConfigService;
import com.nincraft.ninbot.components.config.component.ComponentService;
import com.nincraft.ninbot.components.config.component.ComponentType;
import lombok.Setter;
import lombok.extern.log4j.Log4j2;
import lombok.val;
import net.dv8tion.jda.api.EmbedBuilder;
import net.dv8tion.jda.api.MessageBuilder;
import net.dv8tion.jda.api.entities.Activity;
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.Message;
import net.dv8tion.jda.api.events.user.UserActivityEndEvent;
import net.dv8tion.jda.api.events.user.UserActivityStartEvent;
import net.dv8tion.jda.api.events.user.update.GenericUserPresenceEvent;
import net.dv8tion.jda.api.hooks.ListenerAdapter;
import org.springframework.stereotype.Component;

import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;

@Component
@Log4j2
public class TwitchListener extends ListenerAdapter {

    private ConfigService configService;
    @Setter
    private Set<SlimMember> streamingMembers;
    private LocaleService localeService;
    private ComponentService componentService;
    @Setter
    private List<SlimMember> cooldownList;
    private TwitchAPI twitchAPI;
    private String componentName;

    public TwitchListener(ConfigService configService, LocaleService localeService, TwitchAPI twitchAPI,
            ComponentService componentService) {
        this.configService = configService;
        this.localeService = localeService;
        this.componentService = componentService;
        this.twitchAPI = twitchAPI;
        this.streamingMembers = new HashSet<>();
        this.cooldownList = new ArrayList<>();
        this.componentName = "twitch-announce";
        componentService.registerComponent(componentName, ComponentType.LISTENER);
    }

    @Override
    public void onGenericUserPresence(GenericUserPresenceEvent event) {
        if (componentService.isDisabled(componentName, event.getGuild().getId())) {
            return;
        }
        SlimMember member = new SlimMember(event.getMember().getId(), event.getGuild().getId());
        if (event instanceof UserActivityStartEvent) {
            if (!streamingMembers.contains(member)) {
                val activityStartEvent = (UserActivityStartEvent) event;
                val streamingAnnounceUser = configService.getValuesByName(activityStartEvent.getGuild()
                        .getId(), ConfigConstants.STREAMING_ANNOUNCE_USERS);
                val isStreaming = ((UserActivityStartEvent) event).getNewActivity()
                        .getType()
                        .equals(Activity.ActivityType.STREAMING);
                if (!cooldownList.contains(member) && streamingAnnounceUser.contains(member.getUserId())
                        && isStreaming) {
                    Timer timer = new Timer();
                    announceStream(activityStartEvent);
                    streamingMembers.add(member);
                    timer.schedule(new TwitchAnnounceCooldown(member), Date.from(Instant.now()
                            .plus(30, ChronoUnit.MINUTES)));
                }
            }
        } else if (event instanceof UserActivityEndEvent && event.getMember().getActivities().isEmpty()) {
            removeRole(event.getGuild(), event.getMember());
            streamingMembers.remove(member);
            cooldownList.remove(member);
        }
    }

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


    private void announceStream(UserActivityStartEvent userActivityStartEvent) {
        val serverId = userActivityStartEvent.getGuild().getId();
        val streamingAnnounceChannel = configService.getSingleValueByName(serverId,
                ConfigConstants.STREAMING_ANNOUNCE_CHANNEL);
        streamingAnnounceChannel.ifPresent(streamingAnnounceChannelString -> {
            val guild = userActivityStartEvent.getGuild();
            val channel = guild.getTextChannelById(streamingAnnounceChannelString);
            val username = userActivityStartEvent.getUser().getName();
            val streamingUrl = userActivityStartEvent.getNewActivity().getUrl();
            if (streamingUrl != null) {
                addRole(guild, guild.getMember(userActivityStartEvent.getUser()));
                if (channel != null) {
                    val activity = userActivityStartEvent.getNewActivity();
                    String gameName = activity.getName();
                    String streamTitle = gameName;
                    if (activity.isRich() && activity.asRichPresence().getDetails() != null) {
                        gameName = activity.asRichPresence().getDetails();
                    }
                    channel.sendMessage(buildStreamAnnounceMessage(userActivityStartEvent, username, streamingUrl,
                            gameName, streamTitle, serverId))
                            .queue();
                }
            }
        });
    }

    private Message buildStreamAnnounceMessage(UserActivityStartEvent userActivityStartEvent, String username,
            String streamingUrl, String gameName, String streamTitle, String serverId) {
        String iconUrl = twitchAPI.getBoxArtUrl(gameName);
        ResourceBundle resourceBundle = ResourceBundle.getBundle("lang", localeService.getLocale(serverId));
        val embedMessage = new EmbedBuilder()
                .setAuthor(String.format(resourceBundle.getString("listener.twitch.announce"), username, gameName,
                        streamingUrl), streamingUrl, userActivityStartEvent
                        .getUser()
                        .getAvatarUrl())
                .setTitle(streamTitle)
                .setColor(MessageBuilderHelper.getColor(userActivityStartEvent.getUser().getAvatarUrl()));
        if (iconUrl != null) {
            embedMessage.setFooter(gameName, iconUrl);
        }
        return new MessageBuilder(embedMessage).build();
    }

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

    class TwitchAnnounceCooldown extends TimerTask {

        private SlimMember slimMember;

        TwitchAnnounceCooldown(SlimMember slimMember) {
            this.slimMember = slimMember;
        }

        @Override
        public void run() {
            cooldownList.remove(slimMember);
        }
    }
}

@@ -6473,31 +6473,60 @@
     
-embedMessage.setFooter(
+log.trace(%22Setting boxart with game %7B%7D and URL %7B%7D%22, 
 game

Add logging to investigate twitch announcements issues