package top.quantic.sentry.discord;

import ch.qos.logback.classic.Level;
import ch.qos.logback.classic.LoggerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Component;
import sx.blah.discord.Discord4J;
import sx.blah.discord.api.events.EventSubscriber;
import sx.blah.discord.handle.impl.events.ReadyEvent;
import sx.blah.discord.handle.impl.events.guild.member.UserBanEvent;
import sx.blah.discord.handle.impl.events.shard.DisconnectedEvent;
import sx.blah.discord.handle.impl.events.shard.ReconnectFailureEvent;
import sx.blah.discord.handle.impl.events.shard.ReconnectSuccessEvent;
import top.quantic.sentry.discord.module.DiscordSubscriber;
import top.quantic.sentry.event.LogoutRequestEvent;
import top.quantic.sentry.event.ReconnectEvent;
import top.quantic.sentry.event.ReconnectFailedEvent;
import top.quantic.sentry.event.UserBannedEvent;

import static top.quantic.sentry.discord.util.DiscordUtil.ourBotName;

@Component
public class Supervisor implements DiscordSubscriber {

    private static final Logger log = LoggerFactory.getLogger(Supervisor.class);
    private static final String WEBSOCKET_LOGGER_NAME = "org.eclipse.jetty.websocket";

    private final ApplicationEventPublisher publisher;

    private Level jettyLevel = null;
    private Level d4jLevel = null;

    @Autowired
    public Supervisor(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @EventSubscriber
    public void onReady(ReadyEvent event) {
        log.info("[{}] Discord bot is ready", ourBotName(event));
        publisher.publishEvent(new LogoutRequestEvent(event.getClient()));
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        jettyLevel = context.getLogger(WEBSOCKET_LOGGER_NAME).getLevel();
        d4jLevel = context.getLogger(Discord4J.class).getLevel();
    }

    @EventSubscriber
    public void onReconnectSuccess(ReconnectSuccessEvent event) {
        publisher.publishEvent(new ReconnectEvent(event));
        restoreLevel();
    }

    @EventSubscriber
    public void onReconnectFailure(ReconnectFailureEvent event) {
        publisher.publishEvent(new ReconnectFailedEvent(event));
    }

    @EventSubscriber
    public void onDisconnect(DisconnectedEvent event) {
        log.info("[{}] Discord bot disconnected due to {}", ourBotName(event), event.getReason());
        setTraceLevel();
    }

    @EventSubscriber
    public void onUserBanned(UserBanEvent event) {
        publisher.publishEvent(new UserBannedEvent(event));
    }

    private void setTraceLevel() {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        context.getLogger(WEBSOCKET_LOGGER_NAME).setLevel(Level.TRACE);
        context.getLogger(Discord4J.class).setLevel(Level.TRACE);
    }

    private void restoreLevel() {
        LoggerContext context = (LoggerContext) LoggerFactory.getILoggerFactory();
        if (jettyLevel != null) {
            context.getLogger(WEBSOCKET_LOGGER_NAME).setLevel(jettyLevel);
        }
        if (d4jLevel != null) {
            context.getLogger(Discord4J.class).setLevel(d4jLevel);
        }
    }
}

@@ -1024,16 +1024,69 @@
 Event;%0A%0A
+import java.util.concurrent.atomic.AtomicReference;%0A%0A
 import s
@@ -1452,21 +1452,44 @@
 private 
+final AtomicReference%3C
 Level
+%3E
  jettyLe
@@ -1499,30 +1499,82 @@
  = n
-ull;%0A    private 
+ew AtomicReference%3C%3E(Level.WARN);%0A    private final AtomicReference%3C
 Level
+%3E
  d4j
@@ -1582,19 +1582,49 @@
 evel = n
-ull
+ew AtomicReference%3C%3E(Level.DEBUG)
 ;%0A%0A    @
@@ -1734,221 +1734,8 @@
 er;%0A
-    %7D%0A%0A    @EventSubscriber%0A    public void onReady(ReadyEvent event) %7B%0A        log.info(%22%5B%7B%7D%5D Discord bot is ready%22, ourBotName(event));%0A        publisher.publishEvent(new LogoutRequestEvent(event.getClient()));%0A
     
@@ -1821,16 +1821,21 @@
         
+this.
 jettyLev
@@ -1832,27 +1832,29 @@
 s.jettyLevel
- = 
+.set(
 context.getL
@@ -1888,24 +1888,25 @@
 ).getLevel()
+)
 ;%0A        d4
@@ -1903,24 +1903,29 @@
         
+this.
 d4jLevel
  = conte
@@ -1916,19 +1916,21 @@
 d4jLevel
- = 
+.set(
 context.
@@ -1962,24 +1962,238 @@
 ).getLevel()
+);%0A    %7D%0A%0A    @EventSubscriber%0A    public void onReady(ReadyEvent event) %7B%0A        log.info(%22%5B%7B%7D%5D Discord bot is ready%22, ourBotName(event));%0A        publisher.publishEvent(new LogoutRequestEvent(event.getClient()))
 ;%0A    %7D%0A%0A   
@@ -3256,46 +3256,8 @@
 ();%0A
-        if (jettyLevel != null) %7B%0A    
     
@@ -3324,57 +3324,17 @@
 evel
-);%0A        %7D%0A        if (d4jLevel != null) %7B%0A    
+.get());%0A
     
@@ -3393,20 +3393,16 @@
 evel
-);%0A        %7D
+.get());
 %0A   

Fix trace level reconnects