package io.bazel.rulesscala.scalac;

import io.bazel.rules_scala.diagnostics.Diagnostics;
import scala.reflect.internal.util.Position;
import scala.reflect.internal.util.RangePosition;
import scala.tools.nsc.Settings;
import scala.tools.nsc.reporters.ConsoleReporter;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.*;

public class ProtoReporter extends ConsoleReporter {

  private final Settings settings;
  private final Map<String, List<Diagnostics.Diagnostic>> builder;
  private final Map<Position, Severity> positions = new HashMap<>();
  private final Map<Position, List<String>> messages = new HashMap<>();


  private final boolean isVerbose;
  private final boolean noWarnings;
  private final boolean isPromptSet;
  private final boolean isDebug;

  public ProtoReporter(Settings settings) {
    super(settings);
    this.settings = settings;
    this.isVerbose = (boolean) settings.verbose().value();
    this.noWarnings = settings.nowarnings().value();
    this.isPromptSet = settings.prompt().value();
    this.isDebug = settings.debug().value();
    builder = new LinkedHashMap<>();
  }

  @Override
  public void reset() {
    super.reset();
    positions.clear();
    messages.clear();
  }

  public void writeTo(Path path) throws IOException {
    Diagnostics.TargetDiagnostics.Builder targetDiagnostics = Diagnostics.TargetDiagnostics.newBuilder();
    for (Map.Entry<String, List<Diagnostics.Diagnostic>> entry : builder.entrySet()) {
      targetDiagnostics.addDiagnostics(Diagnostics.FileDiagnostics.newBuilder().setPath(entry.getKey()).addAllDiagnostics(entry.getValue()));
    }
    Files.write(path, targetDiagnostics.build().toByteArray(), StandardOpenOption.CREATE, StandardOpenOption.APPEND);
  }

  @Override
  public void info0(Position pos, String msg, Severity severity, boolean force) {
      super.info0(pos, msg, severity, force);

      Diagnostics.Diagnostic diagnostic = Diagnostics.Diagnostic
          .newBuilder()
          .setRange(positionToRange(pos))
          .setSeverity(convertSeverity(severity))
          .setMessage(msg)
          .build();
      // TODO: Handle generated files
      String uri = "workspace-root://" + pos.source().file().path();
      List<Diagnostics.Diagnostic> diagnostics = builder.computeIfAbsent(uri, key -> new ArrayList());
      diagnostics.add(diagnostic);
  }

  private boolean testAndLog(Position pos, Severity severity, String msg) {
    Position fpos = pos.focus();
    Severity focusSeverity = positions.getOrDefault(fpos, (Severity) INFO());
    boolean supress = false;
    if(focusSeverity.equals(ERROR()))
      supress = true;

    if(focusSeverity.id() > severity.id())
      supress = true;

    if(severity.equals(focusSeverity) && messages.computeIfAbsent(fpos,(key) -> new ArrayList<>()).contains(msg))
      supress = true;

    positions.put(fpos, severity);
    messages.computeIfAbsent(fpos, (key) -> new ArrayList<>()).add(msg);
    return supress;
  }

  private Diagnostics.Severity convertSeverity(Object severity) {
    String stringified = severity.toString().toLowerCase();
    if ("error".equals(stringified)) {
      return Diagnostics.Severity.ERROR;
    } else if ("warning".equals(stringified)) {
        return Diagnostics.Severity.WARNING;
    } else if ("info".equals(stringified)) {
        return Diagnostics.Severity.INFORMATION;
    }
    throw new RuntimeException("Unknown severity: " + stringified);
  }

  private Diagnostics.Range positionToRange(Position pos) {
    if (pos instanceof RangePosition) {
      RangePosition rangePos = (RangePosition) pos;
      int startLine = pos.source().offsetToLine(rangePos.start());
      int endLine = pos.source().offsetToLine(rangePos.end());
      return Diagnostics.Range
          .newBuilder()
          .setStart(Diagnostics.Position.newBuilder()
              .setLine(startLine)
              .setCharacter(rangePos.start() - pos.source().lineToOffset(startLine))
          )
          .setEnd(Diagnostics.Position.newBuilder()
              .setLine(endLine)
              .setCharacter(rangePos.end() - pos.source().lineToOffset(endLine))
              .build())
          .build();
    }
    return Diagnostics.Range
            .newBuilder()
            .setStart(Diagnostics.Position.newBuilder().setLine(pos.line() - 1).setCharacter(pos.column() - 1))
            .setEnd(Diagnostics.Position.newBuilder().setLine(pos.line()))
            .build();
  }
}

@@ -465,43 +465,8 @@
  %7B%0A%0A
-  private final Settings settings;%0A
   pr
@@ -532,592 +532,71 @@
 er;%0A
-  private final Map%3CPosition, Severity%3E positions = new HashMap%3C%3E();%0A  private final Map%3CPosition, List%3CString%3E%3E messages = new HashMap%3C%3E();%0A%0A%0A  private final boolean isVerbose;%0A  private final boolean noWarnings;%0A  private final boolean isPromptSet;%0A  private final boolean isDebug;%0A%0A  public ProtoReporter(Settings settings) %7B%0A    super(settings);%0A    this.settings = settings;%0A    this.isVerbose = (boolean) settings.verbose().value();%0A    this.noWarnings = settings.nowarnings().value();%0A    this.isPromptSet = settings.prompt().value();%0A    this.isDebug = settings.debug().value(
+%0A  public ProtoReporter(Settings settings) %7B%0A    super(settings
 );%0A 
@@ -695,53 +695,8 @@
 ();%0A
-    positions.clear();%0A    messages.clear();%0A
   %7D%0A
@@ -1837,621 +1837,8 @@
  %7D%0A%0A
-  private boolean testAndLog(Position pos, Severity severity, String msg) %7B%0A    Position fpos = pos.focus();%0A    Severity focusSeverity = positions.getOrDefault(fpos, (Severity) INFO());%0A    boolean supress = false;%0A    if(focusSeverity.equals(ERROR()))%0A      supress = true;%0A%0A    if(focusSeverity.id() %3E severity.id())%0A      supress = true;%0A%0A    if(severity.equals(focusSeverity) && messages.computeIfAbsent(fpos,(key) -%3E new ArrayList%3C%3E()).contains(msg))%0A      supress = true;%0A%0A    positions.put(fpos, severity);%0A    messages.computeIfAbsent(fpos, (key) -%3E new ArrayList%3C%3E()).add(msg);%0A    return supress;%0A  %7D%0A%0A
   pr

Delete dead code from ProtoReporter (#1270)