// Copyright (C) 2019 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.copyright;

import static java.util.Objects.requireNonNull;

import com.google.common.base.Strings;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.server.config.PluginConfig;
import com.google.gerrit.server.git.validators.CommitValidationMessage;
import com.google.gerrit.server.git.validators.ValidationMessage;
import com.google.gerrit.server.project.ProjectConfig;
import com.googlesource.gerrit.plugins.copyright.lib.CopyrightPatterns;
import com.googlesource.gerrit.plugins.copyright.lib.CopyrightPatterns.UnknownPatternName;
import com.googlesource.gerrit.plugins.copyright.lib.CopyrightScanner;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashSet;
import java.util.Objects;
import java.util.function.Consumer;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

/** Configuration state for {@link CopyrightValidator} from All-Projects project.config file. */
class ScannerConfig {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  public static final String KEY_ENABLE = "enable";

  static final String KEY_TIME_TEST_MAX = "timeTestMax";
  static final String DEFAULT_REVIEW_LABEL = "Copyright-Review";
  static final String KEY_REVIEWER = "reviewer";
  static final String KEY_CC = "cc";
  static final String KEY_FROM = "fromAccountId";
  static final String KEY_REVIEW_LABEL = "reviewLabel";
  static final String KEY_EXCLUDE = "exclude";
  static final String KEY_FIRST_PARTY = "firstParty";
  static final String KEY_THIRD_PARTY = "thirdParty";
  static final String KEY_FORBIDDEN = "forbidden";
  static final String KEY_EXCLUDE_PATTERN = "excludePattern";
  static final String KEY_FIRST_PARTY_PATTERN = "firstPartyPattern";
  static final String KEY_THIRD_PARTY_PATTERN = "thirdPartyPattern";
  static final String KEY_FORBIDDEN_PATTERN = "forbiddenPattern";
  static final String KEY_ALWAYS_REVIEW_PATH = "alwaysReviewPath";
  static final String KEY_MATCH_PROJECTS = "matchProjects";
  static final String KEY_EXCLUDE_PROJECTS = "excludeProjects";
  static final String KEY_THIRD_PARTY_ALLOWED_PROJECTS = "thirdPartyAllowedProjects";
  private static final String OWNER = "owner ";
  private static final String LICENSE = "license ";

  String pluginName;
  CopyrightScanner scanner;
  String patternSignature;
  final ArrayList<CommitValidationMessage> messages;
  final LinkedHashSet<Pattern> alwaysReviewPath;
  final LinkedHashSet<Pattern> matchProjects;
  final LinkedHashSet<Pattern> excludeProjects;
  final LinkedHashSet<Pattern> thirdPartyAllowedProjects;
  final LinkedHashSet<String> reviewers;
  final LinkedHashSet<String> ccs;
  String reviewLabel;
  boolean defaultEnable;
  int fromAccountId;

  ScannerConfig(String pluginName) {
    this.pluginName = pluginName;
    this.messages = new ArrayList<>();
    this.alwaysReviewPath = new LinkedHashSet<>();
    this.matchProjects = new LinkedHashSet<>();
    this.excludeProjects = new LinkedHashSet<>();
    this.thirdPartyAllowedProjects = new LinkedHashSet<>();
    this.reviewers = new LinkedHashSet<>();
    this.ccs = new LinkedHashSet<>();
    this.reviewLabel = DEFAULT_REVIEW_LABEL;
    this.defaultEnable = false;
    this.fromAccountId = 0;
  }

  /** True when {@link CopyrightValidator} will behave the same with either config. */
  @Override
  public boolean equals(Object other) {
    if (this == other) {
      return true;
    }
    if (other == null) {
      return false;
    }
    if (other instanceof ScannerConfig) {
      ScannerConfig otherConfig = (ScannerConfig) other;
      return defaultEnable == otherConfig.defaultEnable
          && fromAccountId == otherConfig.fromAccountId
          && messages.equals(otherConfig.messages)
          && alwaysReviewPath.equals(otherConfig.alwaysReviewPath)
          && matchProjects.equals(otherConfig.matchProjects)
          && excludeProjects.equals(otherConfig.excludeProjects)
          && thirdPartyAllowedProjects.equals(otherConfig.thirdPartyAllowedProjects)
          && reviewers.equals(otherConfig.reviewers)
          && ccs.equals(otherConfig.ccs)
          && Objects.equals(reviewLabel, otherConfig.reviewLabel)
          && Objects.equals(scanner, otherConfig.scanner);
    }
    return false;
  }

  @Override
  public int hashCode() {
    return Objects.hash(
        defaultEnable,
        fromAccountId,
        messages,
        alwaysReviewPath,
        matchProjects,
        excludeProjects,
        thirdPartyAllowedProjects,
        reviewers,
        ccs,
        reviewLabel,
        scanner);
  }

  /** Formats {@code message} into a message about the plugin configuration. */
  String pluginMessage(String message) {
    return " in " + ProjectConfig.PROJECT_CONFIG + "\n[plugin \"" + pluginName + "\"]\n" + message;
  }

  /** Formats {@code message} into a message about the {@code key = value} line of the config. */
  String pluginKeyValueMessage(String key, String value, String message) {
    StringBuilder sb = new StringBuilder();
    sb.append("  ");
    sb.append(key);
    sb.append(" = ");
    sb.append(value.trim());
    sb.append("\n");
    sb.append("                                            ".substring(0, key.length() + 5));
    sb.append("^\n"); // ^ aligned under start of value in message
    sb.append(message);
    return pluginMessage(sb.toString());
  }

  static CommitValidationMessage errorMessage(String message) {
    return new CommitValidationMessage(message, ValidationMessage.Type.ERROR);
  }

  static CommitValidationMessage warningMessage(String message) {
    return new CommitValidationMessage(message, ValidationMessage.Type.WARNING);
  }

  static CommitValidationMessage hintMessage(String message) {
    return new CommitValidationMessage(message, ValidationMessage.Type.HINT);
  }

  /** Formats {@code message} into a message about a required {@code key} not found in config. */
  String pluginKeyRequired(String key, String message) {
    return pluginMessage("\nno \"" + key + " =\" key was found.\n\n" + message);
  }

  /**
   * Adjusts {@code scannerConfig} state per {@code cfg}.
   *
   * @param builder accumulates the scanner pattern rules used for constructing the scanner
   * @param scannerConfig records the configuration parameter values
   * @param cfg is the source of the configuration
   */
  void readConfigFile(PluginConfig cfg) {
    CopyrightPatterns.RuleSet.Builder builder = CopyrightPatterns.RuleSet.builder();
    // can be disabled in All-Projects and then enabled project-by-project
    defaultEnable = cfg.getBoolean(KEY_ENABLE, defaultEnable);
    fromAccountId = cfg.getInt(KEY_FROM, 0);
    addStringList(cfg, reviewers, KEY_REVIEWER, "reviewer email address");
    addStringList(cfg, ccs, KEY_CC, "CC email address");
    String key = cfg.getString(KEY_REVIEW_LABEL);
    if (!Strings.isNullOrEmpty(key)) {
      reviewLabel = key;
    }
    addPatternList(cfg, alwaysReviewPath, KEY_ALWAYS_REVIEW_PATH, "path pattern");
    addPatternList(cfg, matchProjects, KEY_MATCH_PROJECTS, "project pattern");
    addPatternList(cfg, excludeProjects, KEY_EXCLUDE_PROJECTS, "project pattern");
    addPatternList(
        cfg, thirdPartyAllowedProjects, KEY_THIRD_PARTY_ALLOWED_PROJECTS, "project pattern");
    // exclusions
    addRule(
        cfg,
        rule -> {
          builder.exclude(rule);
        },
        KEY_EXCLUDE);
    addRule(
        cfg,
        rule -> {
          builder.excludePattern(rule);
        },
        KEY_EXCLUDE_PATTERN);
    // first-party
    addRule(
        cfg,
        rule -> {
          builder.addFirstParty(rule);
        },
        KEY_FIRST_PARTY);
    addRulePattern(
        cfg,
        pattern -> {
          builder.addFirstPartyOwner(pattern);
        },
        pattern -> {
          builder.addFirstPartyLicense(pattern);
        },
        KEY_FIRST_PARTY_PATTERN);
    // third-party
    addRule(
        cfg,
        rule -> {
          builder.addThirdParty(rule);
        },
        KEY_THIRD_PARTY);
    addRulePattern(
        cfg,
        pattern -> {
          builder.addThirdPartyOwner(pattern);
        },
        pattern -> {
          builder.addThirdPartyLicense(pattern);
        },
        KEY_THIRD_PARTY_PATTERN);
    // forbidden
    addRule(
        cfg,
        rule -> {
          builder.addForbidden(rule);
        },
        KEY_FORBIDDEN);
    addRulePattern(
        cfg,
        pattern -> {
          builder.addForbiddenOwner(pattern);
        },
        pattern -> {
          builder.addForbiddenLicense(pattern);
        },
        KEY_FORBIDDEN_PATTERN);
    if (hasErrors()) {
      // don't try to compile scanner if errors in configuration
      return;
    }
    CopyrightPatterns.RuleSet rules = builder.build();
    patternSignature = rules.signature();
    scanner =
        new CopyrightScanner(
            rules.firstPartyLicenses,
            rules.thirdPartyLicenses,
            rules.forbiddenLicenses,
            rules.firstPartyOwners,
            rules.thirdPartyOwners,
            rules.forbiddenOwners,
            rules.excludePatterns);
  }

  /** Returns true if {@code project} repository allows third-party code. */
  boolean isThirdPartyAllowed(String project) {
    return matchesAny(project, thirdPartyAllowedProjects);
  }

  /** Returns true if {@code fullPath} matches pattern always requiring review. e.g. PATENT */
  boolean isAlwaysReviewPath(String fullPath) {
    return matchesAny(fullPath, alwaysReviewPath);
  }

  /** Returns true if the configuration triggers any error messages. */
  boolean hasErrors() {
    return messages.stream().anyMatch(m -> m.getType().equals(ValidationMessage.Type.ERROR));
  }

  /** Formats and appends config validation messages to {@code sb}. */
  void appendMessages(StringBuilder sb) {
    for (CommitValidationMessage msg : messages) {
      sb.append("\n\n");
      sb.append(msg.getType().toString());
      sb.append(" ");
      sb.append(msg.getMessage());
    }
  }

  /** Returns true if any pattern in {@code regexes} found in {@code text}. */
  static boolean matchesAny(String text, Collection<Pattern> regexes) {
    requireNonNull(regexes);
    for (Pattern pattern : regexes) {
      if (pattern.matcher(text).find()) {
        return true;
      }
    }
    return false;
  }

  /** Looks up {@code key} in {@code cfg} adding values to {@code dest} as rule names. */
  private void addRule(PluginConfig cfg, Consumer<String> dest, String key) {
    for (String rule : cfg.getStringList(key)) {
      rule = Strings.nullToEmpty(rule).trim();
      if (rule.isEmpty()) {
        messages.add(
            errorMessage(pluginKeyValueMessage(key, rule, "missing license or owner name")));
        continue;
      }
      try {
        dest.accept(rule);
      } catch (UnknownPatternName e) {
        messages.add(errorMessage(pluginKeyValueMessage(key, rule, e.getMessage())));
      }
    }
  }

  /**
   * Looks up {@code key} in {@code cfg} adding {@code owner} patterns to {@code ownerDest} and
   * {@code license} patterns to {@code licenseDest}.
   */
  private void addRulePattern(
      PluginConfig cfg, Consumer<String> ownerDest, Consumer<String> licenseDest, String key) {
    for (String cfgValue : cfg.getStringList(key)) {
      cfgValue = Strings.nullToEmpty(cfgValue).trim();
      if (cfgValue.isEmpty()) {
        messages.add(
            errorMessage(pluginKeyValueMessage(key, cfgValue, "missing owner or license pattern")));
        continue;
      }
      if (cfgValue.toLowerCase().startsWith(OWNER)) {
        String pattern = cfgValue.substring(OWNER.length()).trim();
        ownerDest.accept(pattern);
      } else if (cfgValue.toLowerCase().startsWith(LICENSE)) {
        String pattern = cfgValue.substring(LICENSE.length()).trim();
        licenseDest.accept(pattern);
      } else {
        messages.add(
            errorMessage(
                pluginKeyValueMessage(
                    key, cfgValue, "missing 'owner' or 'license' keyword in '" + cfgValue + "'")));
      }
    }
  }

  /** Looks up {@code key} in {@code cfg} adding values to {@code dest} as strings. */
  private void addStringList(
      PluginConfig cfg, Collection<String> dest, String key, String shortDesc) {
    for (String s : cfg.getStringList(key)) {
      s = Strings.nullToEmpty(s).trim();
      if (s.isEmpty()) {
        messages.add(errorMessage(pluginKeyValueMessage(key, s, "missing " + shortDesc)));
        continue;
      }
      dest.add(s);
    }
  }

  /** Looks up {@code key} in {@code cfg} adding values to {@code dest} as regex patterns. */
  private void addPatternList(
      PluginConfig cfg, Collection<Pattern> dest, String key, String shortDesc) {
    for (String pattern : cfg.getStringList(key)) {
      pattern = Strings.nullToEmpty(pattern).trim();
      if (pattern.isEmpty()) {
        messages.add(errorMessage(pluginKeyValueMessage(key, pattern, "missing " + shortDesc)));
        continue;
      }
      try {
        dest.add(Pattern.compile(pattern));
      } catch (PatternSyntaxException e) {
        messages.add(errorMessage(pluginKeyValueMessage(key, pattern, e.getMessage())));
      }
    }
  }
}
