// Copyright (C) 2017 The Android Open Source Project
//
// 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.googlesource.gerrit.plugins.findowners;

import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.collect.Multimap;
import com.google.gerrit.reviewdb.client.Account;
import com.google.gerrit.reviewdb.client.Project;
import com.google.gerrit.server.account.AccountCache;
import com.google.gerrit.server.account.Accounts;
import java.io.IOException;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.PathMatcher;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.jgit.lib.ObjectReader;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.revwalk.RevTree;
import org.eclipse.jgit.revwalk.RevWalk;
import org.eclipse.jgit.treewalk.TreeWalk;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** Keep all information about owners and owned files. */
class OwnersDb {
  private static final Logger log = LoggerFactory.getLogger(OwnersDb.class);

  private AccountCache accountCache;
  private Accounts accounts;
  private int numOwners = -1; // # of owners of all given files.

  String key = ""; // key to find this OwnersDb in a cache.
  String revision = ""; // tip of branch revision, where OWENRS were found.
  Map<String, Set<String>> dir2Globs = new HashMap<>(); // directory to file globs in the directory
  Map<String, Set<String>> owner2Paths = new HashMap<>(); // owner email to owned dirs or file globs
  Map<String, Set<String>> path2Owners = new HashMap<>(); // dir or file glob to owner emails
  Set<String> readDirs = new HashSet<>(); // directories in which we have checked OWNERS
  Set<String> stopLooking = new HashSet<>(); // directories where OWNERS has "set noparent"
  Map<String, String> preferredEmails = new HashMap<>(); // owner email to preferred email
  List<String> errors = new ArrayList<>(); // error messages

  OwnersDb() {}

  OwnersDb(
      AccountCache accountCache,
      Accounts accounts,
      String key,
      Repository repository,
      Project.NameKey project,
      String branch,
      Collection<String> files) {
    this.accountCache = accountCache;
    this.accounts = accounts;
    this.key = key;
    preferredEmails.put("*", "*");
    String ownersFileName = Config.getOwnersFileName(project);
    for (String fileName : files) {
      // Find OWNERS in fileName's directory and parent directories.
      // Stop looking for a parent directory if OWNERS has "set noparent".
      fileName = Util.normalizedFilePath(fileName);
      String dir = Util.normalizedDirPath(fileName); // e.g. dir = ./d1/d2
      while (!readDirs.contains(dir)) {
        readDirs.add(dir);
        String filePath = (dir + "/" + ownersFileName).substring(2); // remove "./"
        String content = getRepositoryFile(repository, branch, filePath);
        if (content != null && !content.equals("")) {
          addFile(dir + "/", dir + "/" + ownersFileName, content.split("\\R+"));
        }
        if (stopLooking.contains(dir + "/") || !dir.contains("/")) {
          break; // stop looking through parent directory
        }
        dir = Util.getDirName(dir); // go up one level
      }
    }
    countNumOwners(files);
    try {
      revision = repository.getRef(branch).getObjectId().getName();
    } catch (IOException e) {
      log.error("Fail to get branch revision", e);
      revision = "";
    }
  }

  int getNumOwners() {
    return (numOwners >= 0) ? numOwners : owner2Paths.keySet().size();
  }

  private void countNumOwners(Collection<String> files) {
    Map<String, Set<String>> file2Owners = findOwners(files, null);
    if (file2Owners != null) {
      Set<String> emails = new HashSet<>();
      file2Owners.values().forEach(emails::addAll);
      numOwners = emails.size();
    } else {
      numOwners = owner2Paths.keySet().size();
    }
  }

  void addOwnerPathPair(String owner, String path) {
    Util.addToMap(owner2Paths, owner, path);
    Util.addToMap(path2Owners, path, owner);
    if (path.length() > 0 && path.charAt(path.length() - 1) != '/') {
      Util.addToMap(dir2Globs, Util.getDirName(path) + "/", path); // A file glob.
    }
  }

  void addPreferredEmails(Set<String> ownerEmails) {
    List<String> owners = new ArrayList<String>(ownerEmails);
    owners.removeIf(o -> preferredEmails.get(o) != null);
    if (owners.size() > 0) {
      String[] emails = new String[owners.size()];
      owners.toArray(emails);
      Multimap<String, Account.Id> email2ids = null;
      try {
        email2ids = accounts.byEmails(emails);
      } catch (Exception e) {
        log.error("accounts.byEmails failed with exception: ", e);
      }
      for (String owner : emails) {
        String email = owner;
        try {
          if (email2ids == null) {
            errors.add(owner);
          } else {
            Collection<Account.Id> ids = email2ids.get(owner);
            if (ids == null || ids.size() != 1) {
              errors.add(owner);
            } else {
              email = accountCache.get(ids.iterator().next()).getAccount().getPreferredEmail();
            }
          }
        } catch (Exception e) {
          log.error("Fail to find preferred email of " + owner, e);
          errors.add(owner);
        }
        preferredEmails.put(owner, email);
      }
    }
  }

  void addFile(String dirPath, String filePath, String[] lines) {
    Parser.Result result = Parser.parseFile(dirPath, filePath, lines);
    if (result.stopLooking) {
      stopLooking.add(dirPath);
    }
    addPreferredEmails(result.owner2paths.keySet());
    for (String owner : result.owner2paths.keySet()) {
      String email = preferredEmails.get(owner);
      for (String path : result.owner2paths.get(owner)) {
        addOwnerPathPair(email, path);
      }
    }
    if (Config.getReportSyntaxError()) {
      result.warnings.forEach(w -> log.warn(w));
      result.errors.forEach(w -> log.error(w));
    }
  }

  private void addOwnerWeights(
      ArrayList<String> paths,
      ArrayList<Integer> distances,
      String file,
      Map<String, Set<String>> file2Owners,
      Map<String, OwnerWeights> map) {
    for (int i = 0; i < paths.size(); i++) {
      Set<String> owners = path2Owners.get(paths.get(i));
      if (owners == null) {
        continue;
      }
      for (String name : owners) {
        Util.addToMap(file2Owners, file, name);
        if (map == null) {
          continue;
        }
        if (map.containsKey(name)) {
          map.get(name).addFile(file, distances.get(i));
        } else {
          map.put(name, new OwnerWeights(file, distances.get(i)));
        }
      }
    }
  }

  /** Quick method to find owner emails of every file. */
  Map<String, Set<String>> findOwners(Collection<String> files) {
    return findOwners(files, null);
  }

  /** Returns owner emails of every file and set up ownerWeights. */
  Map<String, Set<String>> findOwners(
      Collection<String> files, Map<String, OwnerWeights> ownerWeights) {
    return findOwners(files.toArray(new String[0]), ownerWeights);
  }

  /** Returns true if path has '*' owner. */
  private boolean findStarOwner(
      String path, int distance, ArrayList<String> paths, ArrayList<Integer> distances) {
    Set<String> owners = path2Owners.get(path);
    if (owners != null) {
      paths.add(path);
      distances.add(distance);
      if (owners.contains("*")) {
        return true;
      }
    }
    return false;
  }

  /** Returns owner emails of every file and set up ownerWeights. */
  Map<String, Set<String>> findOwners(String[] files, Map<String, OwnerWeights> ownerWeights) {
    // Returns a map of file to set of owner emails.
    // If ownerWeights is not null, add to it owner to distance-from-dir;
    // a distance of 1 is the lowest/closest possible distance
    // (which makes the subsequent math easier).
    Map<String, Set<String>> file2Owners = new HashMap<>();
    for (String fileName : files) {
      fileName = Util.normalizedFilePath(fileName);
      String dirPath = Util.normalizedDirPath(fileName);
      String baseName = fileName.substring(dirPath.length() + 1);
      int distance = 1;
      FileSystem fileSystem = FileSystems.getDefault();
      // Collect all matched (path, distance) in all OWNERS files for
      // fileName. Add them only if there is no special "*" owner.
      ArrayList<String> paths = new ArrayList<>();
      ArrayList<Integer> distances = new ArrayList<>();
      boolean foundStar = false;
      while (true) {
        int savedSizeOfPaths = paths.size();
        if (dir2Globs.containsKey(dirPath + "/")) {
          Set<String> patterns = dir2Globs.get(dirPath + "/");
          for (String pat : patterns) {
            PathMatcher matcher = fileSystem.getPathMatcher("glob:" + pat);
            if (matcher.matches(Paths.get(dirPath + "/" + baseName))) {
              foundStar |= findStarOwner(pat, distance, paths, distances);
              // Do not break here, a file could match multiple globs
              // with different owners.
              // OwnerWeights.add won't add duplicated files.
            }
          }
          // NOTE: A per-file directive can only specify owner emails,
          // not "set noparent".
        }
        // If baseName does not match per-file glob, paths is not changed.
        // Then we should check the general non-per-file owners.
        if (paths.size() == savedSizeOfPaths) {
          foundStar |= findStarOwner(dirPath + "/", distance, paths, distances);
        }
        if (foundStar // This file can be approved by anyone, no owner.
            || stopLooking.contains(dirPath + "/") // stop looking parent
            || !dirPath.contains("/") /* root */) {
          break;
        }
        if (paths.size() != savedSizeOfPaths) {
          distance++; // increase distance for each found OWNERS
        }
        dirPath = Util.getDirName(dirPath); // go up one level
      }
      if (!foundStar) {
        addOwnerWeights(paths, distances, fileName, file2Owners, ownerWeights);
      }
    }
    return file2Owners;
  }

  /** Returns file content or empty string; uses Repository. */
  static String getRepositoryFile(Repository repo, String branch, String file) {
    try (RevWalk revWalk = new RevWalk(repo)) {
      RevTree tree = revWalk.parseCommit(repo.resolve(branch)).getTree();
      ObjectReader reader = revWalk.getObjectReader();
      TreeWalk treeWalk = TreeWalk.forPath(reader, file, tree);
      if (treeWalk != null) {
        return new String(reader.open(treeWalk.getObjectId(0)).getBytes(), UTF_8);
      }
    } catch (IOException e) {
      log.error("get file " + file, e);
    }
    return "";
  }
}
