package com.hubspot.blazar.util;

import java.util.Set;

import com.google.common.base.Optional;
import com.google.inject.Inject;
import com.hubspot.blazar.base.GitInfo;
import com.hubspot.blazar.base.Module;
import com.hubspot.blazar.base.ModuleBuild;
import com.hubspot.blazar.base.RepositoryBuild;
import com.hubspot.blazar.data.service.BranchService;
import com.hubspot.blazar.data.service.ModuleBuildService;
import com.hubspot.blazar.data.service.ModuleService;
import com.hubspot.blazar.data.service.RepositoryBuildService;
import com.ullink.slack.simpleslackapi.SlackAttachment;
import com.ullink.slack.simpleslackapi.SlackChannel;
import com.ullink.slack.simpleslackapi.SlackSession;

public class SlackUtils {

  private BranchService branchService;
  private ModuleService moduleService;
  private ModuleBuildService moduleBuildService;
  private RepositoryBuildService repositoryBuildService;
  private BlazarUrlHelper blazarUrlHelper;

  @Inject
  public SlackUtils(BranchService branchService,
                    ModuleService moduleService,
                    ModuleBuildService moduleBuildService,
                    RepositoryBuildService repositoryBuildService,
                    BlazarUrlHelper blazarUrlHelper) {

    this.branchService = branchService;
    this.moduleService = moduleService;
    this.moduleBuildService = moduleBuildService;
    this.repositoryBuildService = repositoryBuildService;
    this.blazarUrlHelper = blazarUrlHelper;
  }

  public static Optional<SlackChannel> getChannelByName(SlackSession session, String name) {
    return Optional.fromNullable(session.findChannelByName(name));
  }


  public SlackAttachment buildSlackAttachment(RepositoryBuild build) {
    String title = buildNormalStateMessage(build);
    SlackAttachment attachment = makeAttachment(title);
    attachment.setTitleLink(blazarUrlHelper.getBlazarUiLink(build));
    attachment.setColor(getColor(build.getState()));

    if (build.getState().equals(RepositoryBuild.State.SUCCEEDED)) {
      return attachment;
    }
    attachment.setText("The failing modules were:");

    Set<ModuleBuild> builtModules = moduleBuildService.getByRepositoryBuild(build.getId().get());
    for (ModuleBuild b : builtModules) {
      // If a build fails, SUCCEEDED & Skipped & CANCELLED are common, and unnecessary to include
      if (!b.getState().equals(ModuleBuild.State.SUCCEEDED) && !b.getState().equals(ModuleBuild.State.CANCELLED) && !b.getState().equals(ModuleBuild.State.SKIPPED)) {
        Module m = moduleService.get(b.getModuleId()).get();
        attachment.addField(m.getName(), b.getState().name().toLowerCase(), true);
      }
    }
    return attachment;
  }

  public SlackAttachment buildSlackAttachment(ModuleBuild build) {
    String title = buildNormalStateMessage(build);
    SlackAttachment attachment = makeAttachment(title);
    attachment.setTitleLink(blazarUrlHelper.getBlazarUiLink(build));
    attachment.setColor(getColor(build.getState()));
    return attachment;
  }

  public String buildNormalStateMessage(ModuleBuild build) {
    Module module = moduleService.get(build.getModuleId()).get();
    GitInfo gitInfo = branchService.get(repositoryBuildService.get(build.getRepoBuildId()).get().getBranchId()).get();
    return String.format("Module Build %s-%s-%s#%d finished with state %s", gitInfo.getRepository(), gitInfo.getBranch(), module.getName(), build.getBuildNumber(), build.getState().toString().toLowerCase());
  }

  public String buildNormalStateMessage(RepositoryBuild build) {
    GitInfo gitInfo = branchService.get(build.getBranchId()).get();
    return String.format("Repository Build %s-%s#%d finished with state %s", gitInfo.getRepository(), gitInfo.getBranch(), build.getBuildNumber(), build.getState().toString().toLowerCase());
  }

  private String getColor(ModuleBuild.State state) {
    String color;
    switch (state) {
      case SUCCEEDED:
        color = "good";
        break;
      case CANCELLED:
        color = "warning";
        break;
      case SKIPPED:
        color = "grey";
        break;
      case FAILED:
        color = "danger";
        break;
      default:
        color = "blue";
        break;
    }
    return color;
  }

  private String getColor(RepositoryBuild.State state) {
    String color;
    switch (state) {
      case SUCCEEDED:
        color = "good";
        break;
      case CANCELLED:
        color = "warning";
        break;
      case UNSTABLE:
        color = "danger";
        break;
      case FAILED:
        color = "danger";
        break;
      default:
        color = "blue";
        break;
    }
    return color;
  }

  private static SlackAttachment makeAttachment(String title) {
    return new SlackAttachment(title, title, "", "");
  }
}

@@ -2326,16 +2326,75 @@
 include%0A
+      Module m = moduleService.get(b.getModuleId()).get();%0A
       if
@@ -2395,17 +2395,16 @@
     if (
-!
 b.getSta
@@ -2437,23 +2437,79 @@
 ate.
-SUCCEED
+FAILED) %7C%7C build.getState().equals(RepositoryBuild.State.CANCELL
 ED) && 
-!
 b.ge
@@ -2556,79 +2556,264 @@
 LED)
- && !b.getState().equals(ModuleBuild.State.SKIPPED)) %7B%0A        Module m
+) %7B%0A        attachment.addField(m.getName(), b.getState().name().toLowerCase(), true);%0A      %7D else if (b.getState().equals(ModuleBuild.State.SKIPPED) && build.getState().equals(RepositoryBuild.State.UNSTABLE)) %7B%0A        Optional%3CModuleBuild%3E maybePrevious
  = m
@@ -2809,32 +2809,37 @@
 revious = module
+Build
 Service.get(b.ge
@@ -2837,115 +2837,508 @@
 .get
-(b.getModuleId()).get();%0A        attachment.addField(m.getName(), b.getState().name().toLowerCase(), true);
+PreviousBuild(b);%0A        if (maybePrevious.isPresent() && (maybePrevious.get().getState().equals(ModuleBuild.State.CANCELLED) %7C%7C maybePrevious.get().getState().equals(ModuleBuild.State.FAILED))) %7B%0A          attachment.addField(m.getName(), String.format(%22Unstable, last attempted build was in branch build #%25d%22, maybePrevious.get().getBuildNumber()), false);%0A        %7D else if (!maybePrevious.isPresent()) %7B%0A          attachment.addField(m.getName(), %22This module has never built.%22, true);%0A        %7D
 %0A   

Update SlackUtils to include messaging about previous stable builds