// Copyright 2018 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.devtools.build.importdeps;

import com.google.common.collect.HashMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.importdeps.AbstractClassEntryState.IncompleteState;
import com.google.devtools.build.importdeps.ResultCollector.MissingMember;
import com.google.devtools.build.lib.view.proto.Deps.Dependencies;
import com.google.devtools.build.lib.view.proto.Deps.Dependency;
import com.google.devtools.build.lib.view.proto.Deps.Dependency.Kind;
import java.io.Closeable;
import java.io.IOError;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Path;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
import java.util.stream.Stream;
import java.util.zip.ZipFile;
import javax.annotation.Nullable;
import org.objectweb.asm.ClassReader;

/**
 * Checker that checks the classes in the input jars have complete dependencies. If not, output the
 * missing dependencies to a file.
 */
public final class ImportDepsChecker implements Closeable {

  private final ClassCache classCache;
  private final ResultCollector resultCollector;
  private final ImmutableList<Path> inputJars;
  private final ImmutableMap<Path, String> pathToTargetMap;
  private final Function<ClassInfo, String> classInfoLabelFunc;

  public ImportDepsChecker(
      ImmutableList<Path> bootclasspath,
      ImmutableList<Path> directClasspath,
      ImmutableList<Path> classpath,
      ImmutableList<Path> inputJars)
      throws IOException {
    this.classCache = new ClassCache(bootclasspath, directClasspath, classpath, inputJars);
    this.resultCollector = new ResultCollector();
    this.inputJars = inputJars;
    this.pathToTargetMap = buildPathToTargetMap(bootclasspath, classpath, inputJars);
    this.classInfoLabelFunc =
        klass -> {
          String klassName = klass.internalName().replace('/', '.');
          String targetName = pathToTargetMap.get(klass.jarPath());
          if (targetName != null) {
            int index = targetName.lastIndexOf('/');
            if (index >= 0) {
              // Just print the target name without the full path, as the Bazel tests have
              // different full paths of targets.
              targetName = targetName.substring(index + 1);
            }
            return klassName + " (in " + targetName + ")";
          } else {
            return klassName;
          }
        };
  }

  /**
   * Checks for dependency problems in the given input jars agains the classpath.
   *
   * @return {@literal true} for no problems, {@literal false} otherwise.
   */
  public boolean check() throws IOException {
    for (Path path : inputJars) {
      try (ZipFile jarFile = new ZipFile(path.toFile())) {
        jarFile
            .stream()
            .forEach(
                entry -> {
                  String name = entry.getName();
                  if (!name.endsWith(".class")) {
                    return;
                  }
                  try (InputStream inputStream = jarFile.getInputStream(entry)) {
                    ClassReader reader = new ClassReader(inputStream);
                    DepsCheckerClassVisitor checker =
                        new DepsCheckerClassVisitor(classCache, resultCollector);
                    reader.accept(checker, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
                  } catch (IOException e) {
                    throw new IOError(e);
                  } catch (RuntimeException e) {
                    System.err.printf(
                        "A runtime exception occurred when processing the class %s "
                            + "in the zip file %s\n",
                        name, path);
                    throw e;
                  }
                });
      }
    }
    return resultCollector.isEmpty();
  }

  /** Emit the jdeps proto. The parameter ruleLabel is optional, indicated with the empty string. */
  public Dependencies emitJdepsProto(String ruleLabel) {
    Dependencies.Builder builder = Dependencies.newBuilder();
    ImmutableList<Path> paths = classCache.collectUsedJarsInRegularClasspath();
    // TODO(b/77723273): Consider "implicit" for Jars only needed to resolve supertypes
    paths.forEach(
        path ->
            builder.addDependency(
                Dependency.newBuilder().setKind(Kind.EXPLICIT).setPath(path.toString()).build()));
    return builder.setRuleLabel(ruleLabel).setSuccess(true).build();
  }

  private static final String INDENT = "    ";

  public String computeResultOutput(String ruleLabel) {
    StringBuilder builder = new StringBuilder();
    ImmutableList<String> missingClasses = resultCollector.getSortedMissingClassInternalNames();
    outputMissingClasses(builder, missingClasses);

    ImmutableList<IncompleteState> incompleteClasses = resultCollector.getSortedIncompleteClasses();
    outputIncompleteClasses(builder, incompleteClasses);

    ImmutableList<MissingMember> missingMembers = resultCollector.getSortedMissingMembers();
    outputMissingMembers(builder, missingMembers);

    outputStatistics(builder, missingClasses, incompleteClasses, missingMembers);

    emitAddDepCommandForIndirectJars(ruleLabel, builder);
    return builder.toString();
  }

  private void emitAddDepCommandForIndirectJars(String ruleLabel, StringBuilder builder) {
    ImmutableList<Path> indirectJars = resultCollector.getSortedIndirectDeps();
    if (!indirectJars.isEmpty()) {
      ImmutableList<String> labels = extractLabels(indirectJars);
      if (ruleLabel.isEmpty() || labels.isEmpty()) {
        builder
            .append(
                "*** Missing strict dependencies on the following Jars which don't carry "
                    + "rule labels.\nPlease determine the originating rules, e.g., using Bazel's "
                    + "'query' command, and add them to the dependencies of ")
            .append(ruleLabel.isEmpty() ? inputJars : ruleLabel)
            .append('\n');
        for (Path jar : indirectJars) {
          builder.append(jar).append('\n');
        }
      } else {
        builder.append("*** Command to add missing strict dependencies: ***\n\n");
        builder.append("    add_dep ");
        for (String indirectLabel : labels) {
          builder.append(indirectLabel).append(" ");
        }
        builder.append(ruleLabel).append('\n');
      }
    }
  }

  private void outputStatistics(
      StringBuilder builder,
      ImmutableList<String> missingClasses,
      ImmutableList<IncompleteState> incompleteClasses,
      ImmutableList<MissingMember> missingMembers) {
    if (missingClasses.size() + incompleteClasses.size() + missingMembers.size() != 0) {
      builder
          .append("===Total===\n")
          .append("missing=")
          .append(missingClasses.size())
          .append('\n')
          .append("incomplete=")
          .append(incompleteClasses.size())
          .append('\n')
          .append("missing_members=")
          .append(missingMembers.size())
          .append('\n');
    }
  }

  private void outputMissingMembers(
      StringBuilder builder, ImmutableList<MissingMember> missingMembers) {
    LinkedHashSet<ClassInfo> classesWithMissingMembers = new LinkedHashSet<>();
    for (MissingMember missing : missingMembers) {
      builder
          .append("Missing member '")
          .append(missing.memberName())
          .append("' in class ")
          .append(missing.owner().internalName().replace('/', '.'))
          .append(" : name=")
          .append(missing.memberName())
          .append(", descriptor=")
          .append(missing.descriptor())
          .append('\n');
      classesWithMissingMembers.add(missing.owner());
    }
    if (!classesWithMissingMembers.isEmpty()) {
      builder.append("The class hierarchies of the classes with missing members:").append("\n");
      classesWithMissingMembers.forEach(
          missingClass -> printClassHierarchy(missingClass, builder, classInfoLabelFunc, "    "));
    }
  }

  private static void printClassHierarchy(
      ClassInfo klass,
      StringBuilder builder,
      Function<ClassInfo, String> labelFunction,
      String indent) {
    builder.append(indent).append(labelFunction.apply(klass)).append('\n');
    String superIndent = indent + "    ";

    for (ClassInfo superClass : klass.superClasses()) {
      printClassHierarchy(superClass, builder, labelFunction, superIndent);
    }
  }

  private void outputIncompleteClasses(
      StringBuilder builder, ImmutableList<IncompleteState> incompleteClasses) {
    new LinkedHashMap<>();
    HashMultimap<String, ClassInfo> map = HashMultimap.create();
    for (IncompleteState incomplete : incompleteClasses) {
      ResolutionFailureChain chain = incomplete.resolutionFailureChain();
      map.putAll(chain.getMissingClassesWithSubclasses());
    }
    map.asMap()
        .entrySet()
        .stream()
        .sorted(Map.Entry.comparingByKey())
        .forEach(
            entry -> {
              builder
                  .append("Indirectly missing class ")
                  .append(entry.getKey().replace('/', '.'))
                  .append(". Referenced by:")
                  .append('\n');
              entry
                  .getValue()
                  .stream()
                  .distinct()
                  .sorted()
                  .forEach(
                      reference -> {
                        builder
                            .append(INDENT)
                            .append(classInfoLabelFunc.apply(reference))
                            .append('\n');
                      });
            });
  }

  private void outputMissingClasses(StringBuilder builder, ImmutableList<String> missingClasses) {
    for (String missing : missingClasses) {
      builder.append("Missing ").append(missing.replace('/', '.')).append('\n');
    }
  }

  private static ImmutableMap<Path, String> buildPathToTargetMap(ImmutableList<Path>... pathList) {
    ImmutableMap.Builder<Path, String> labels = ImmutableMap.builder();
    Stream.of(pathList)
        .flatMap(ImmutableList::stream)
        .distinct()
        .forEach(
            path -> {
              String label = extractLabel(path);
              if (label != null) {
                labels.put(path, label);
              }
            });
    return labels.build();
  }

  private ImmutableList<String> extractLabels(ImmutableList<Path> jars) {
    return jars.parallelStream()
        .map(pathToTargetMap::get)
        .filter(Objects::nonNull)
        .distinct()
        .sorted()
        .collect(ImmutableList.toImmutableList());
  }

  static final Attributes.Name TARGET_LABEL = new Attributes.Name("Target-Label");
  static final Attributes.Name INJECTING_RULE_KIND = new Attributes.Name("Injecting-Rule-Kind");

  @Nullable
  private static String extractLabel(Path jarPath) {
    try (JarFile jar = new JarFile(jarPath.toFile())) {
      Manifest manifest = jar.getManifest();
      if (manifest == null) {
        return null;
      }
      Attributes attributes = manifest.getMainAttributes();
      if (attributes == null) {
        return null;
      }
      String targetLabel = (String) attributes.get(TARGET_LABEL);
      String injectingRuleKind = (String) attributes.get(INJECTING_RULE_KIND);
      if (injectingRuleKind == null) {
        return targetLabel;
      } else {
        return String.format("\"%s %s\"", targetLabel, injectingRuleKind);
      }
    } catch (IOException e) {
      throw new UncheckedIOException(e);
    }
  }

  @Override
  public void close() throws IOException {
    classCache.close();
  }
}
