package com.hubspot.singularity.sentry;

import java.util.Collections;
import java.util.Map;

import javax.inject.Singleton;
import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.base.Optional;
import com.google.common.base.Strings;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.name.Named;
import com.hubspot.singularity.SingularityMainModule;
import com.hubspot.singularity.SingularityUser;
import com.hubspot.singularity.config.SentryConfiguration;

import net.kencochrane.raven.Raven;
import net.kencochrane.raven.RavenFactory;
import net.kencochrane.raven.event.Event;
import net.kencochrane.raven.event.EventBuilder;
import net.kencochrane.raven.event.interfaces.ExceptionInterface;
import net.kencochrane.raven.event.interfaces.HttpInterface;
import net.kencochrane.raven.event.interfaces.UserInterface;

@Singleton
public class SingularityExceptionNotifier {
  private static final Logger LOG = LoggerFactory.getLogger(SingularityExceptionNotifier.class);

  private final Optional<Raven> raven;
  private final Optional<SentryConfiguration> sentryConfiguration;
  private final Provider<Optional<HttpServletRequest>> requestProvider;
  private final Provider<Optional<SingularityUser>> userProvider;

  @Inject
  public SingularityExceptionNotifier(Optional<SentryConfiguration> sentryConfiguration, @Named(SingularityMainModule.CURRENT_HTTP_REQUEST) Provider<Optional<HttpServletRequest>> requestProvider, Provider<Optional<SingularityUser>> userProvider) {
    this.sentryConfiguration = sentryConfiguration;
    this.requestProvider = requestProvider;
    this.userProvider = userProvider;
    if (sentryConfiguration.isPresent()) {
      this.raven = Optional.of(RavenFactory.ravenInstance(sentryConfiguration.get().getDsn()));
    } else {
      this.raven = Optional.absent();
    }
  }

  private String getPrefix() {
    if (!sentryConfiguration.isPresent() || Strings.isNullOrEmpty(sentryConfiguration.get().getPrefix())) {
      return "";
    }

    return sentryConfiguration.get().getPrefix() + " ";
  }

  private Optional<String> getCurrentUrl() {
    final Optional<HttpServletRequest> request = requestProvider.get();

    if (request.isPresent()) {
      return Optional.of(request.get().getRequestURI());
    } else {
      return Optional.absent();
    }
  }

  private String getCallingClassName(StackTraceElement[] stackTrace) {
    if (stackTrace != null && stackTrace.length > 2) {
      return stackTrace[2].getClassName();
    } else {
      return "(unknown)";
    }
  }

  private void sendEvent(Raven raven, final EventBuilder eventBuilder) {
    raven.runBuilderHelpers(eventBuilder);

    raven.sendEvent(eventBuilder.build());
  }

  public void notify(Throwable t) {
    notify(t, Collections.<String, String>emptyMap());
  }

  public void notify(Throwable t, Map<String, String> extraData) {
    if (!raven.isPresent()) {
      return;
    }

    final StackTraceElement[] currentThreadStackTrace = Thread.currentThread().getStackTrace();

    final EventBuilder eventBuilder = new EventBuilder()
            .withCulprit(getPrefix() + t.getMessage())
            .withMessage(Strings.nullToEmpty(t.getMessage()))
            .withLevel(Event.Level.ERROR)
            .withLogger(getCallingClassName(currentThreadStackTrace))
            .withSentryInterface(new ExceptionInterface(t));

    final Optional<HttpServletRequest> maybeRequest = requestProvider.get();

    if (maybeRequest.isPresent()) {
      eventBuilder.withSentryInterface(new HttpInterface(maybeRequest.get()));
    }

    final Optional<SingularityUser> maybeUser = userProvider.get();

    if (maybeUser.isPresent()) {
      eventBuilder.withSentryInterface(new UserInterface(maybeUser.get().getId(), maybeUser.get().getId(), "", maybeUser.get().getEmail().or("")));
    }

    if (extraData != null && !extraData.isEmpty()) {
      for (Map.Entry<String, String> entry : extraData.entrySet()) {
        eventBuilder.withExtra(entry.getKey(), entry.getValue());
      }
    }

    sendEvent(raven.get(), eventBuilder);
  }

  public void notify(String subject) {
    notify(subject, Collections.<String, String>emptyMap());
  }

  public void notify(String subject, Map<String, String> extraData) {
    if (!raven.isPresent()) {
      return;
    }

    final StackTraceElement[] currentThreadStackTrace = Thread.currentThread().getStackTrace();

    final EventBuilder eventBuilder = new EventBuilder()
            .withMessage(getPrefix() + subject)
            .withLevel(Event.Level.ERROR)
            .withLogger(getCallingClassName(currentThreadStackTrace));

    final Optional<HttpServletRequest> maybeRequest = requestProvider.get();

    if (maybeRequest.isPresent()) {
      eventBuilder.withSentryInterface(new HttpInterface(maybeRequest.get()));
    }

    if (extraData != null && !extraData.isEmpty()) {
      for (Map.Entry<String, String> entry : extraData.entrySet()) {
        eventBuilder.withExtra(entry.getKey(), entry.getValue());
      }
    }

    sendEvent(raven.get(), eventBuilder);
  }
}

@@ -169,66 +169,8 @@
 t;%0A%0A
-import org.slf4j.Logger;%0Aimport org.slf4j.LoggerFactory;%0A%0A
 impo
@@ -205,16 +205,16 @@
 tional;%0A
+
 import c
@@ -929,106 +929,8 @@
 r %7B%0A
-  private static final Logger LOG = LoggerFactory.getLogger(SingularityExceptionNotifier.class);%0A%0A
   pr
@@ -1922,24 +1922,24 @@
  %22%22;%0A    %7D%0A%0A
+
     return s
@@ -1991,270 +1991,8 @@
  %7D%0A%0A
-  private Optional%3CString%3E getCurrentUrl() %7B%0A    final Optional%3CHttpServletRequest%3E request = requestProvider.get();%0A%0A    if (request.isPresent()) %7B%0A      return Optional.of(request.get().getRequestURI());%0A    %7D else %7B%0A      return Optional.absent();%0A    %7D%0A  %7D%0A%0A
   pr

remove unused code