// Copyright (C) 2021 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.google.gerrit.server.project;

import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.entities.LabelType;
import com.google.gerrit.entities.SubmitRecord;
import com.google.gerrit.entities.SubmitRecord.Label;
import com.google.gerrit.entities.SubmitRequirement;
import com.google.gerrit.entities.SubmitRequirementExpression;
import com.google.gerrit.entities.SubmitRequirementExpressionResult;
import com.google.gerrit.entities.SubmitRequirementExpressionResult.Status;
import com.google.gerrit.entities.SubmitRequirementResult;
import com.google.gerrit.server.query.change.ChangeData;
import com.google.gerrit.server.query.change.ChangeQueryBuilder;
import com.google.gerrit.server.rules.DefaultSubmitRule;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;
import org.eclipse.jgit.lib.ObjectId;

/**
 * Convert {@link com.google.gerrit.entities.SubmitRecord} entities to {@link
 * com.google.gerrit.entities.SubmitRequirementResult}s.
 */
public class SubmitRequirementsAdapter {
  private static final FluentLogger logger = FluentLogger.forEnclosingClass();

  private SubmitRequirementsAdapter() {}

  /**
   * Retrieve legacy submit records (created by label functions and other {@link
   * com.google.gerrit.server.rules.SubmitRule}s) and convert them to submit requirement results.
   */
  public static Map<SubmitRequirement, SubmitRequirementResult> getLegacyRequirements(
      ChangeData cd) {
    // We use SubmitRuleOptions.defaults() which does not recompute submit rules for closed changes.
    // This doesn't have an effect since we never call this class (i.e. to evaluate submit
    // requirements) for closed changes.
    List<SubmitRecord> records = cd.submitRecords(SubmitRuleOptions.defaults());
    boolean areForced =
        records.stream().anyMatch(record -> SubmitRecord.Status.FORCED.equals(record.status));
    List<LabelType> labelTypes = cd.getLabelTypes().getLabelTypes();
    ObjectId commitId = cd.currentPatchSet().commitId();
    Map<String, List<SubmitRequirementResult>> srsByName =
        records.stream()
            // Filter out the "FORCED" submit record. This is a marker submit record that was just
            // used to indicate that all other records were forced. "FORCED" means that the change
            // was pushed with the %submit option bypassing submit rules.
            .filter(r -> !SubmitRecord.Status.FORCED.equals(r.status))
            .map(r -> createResult(r, labelTypes, commitId, areForced))
            .flatMap(List::stream)
            .collect(Collectors.groupingBy(sr -> sr.submitRequirement().name()));

    // We convert submit records to submit requirements by generating a separate
    // submit requirement result for each available label in each submit record.
    // The SR status is derived from the label status of the submit record.
    // This conversion might result in duplicate entries.
    // One such example can be a prolog rule emitting the same label name twice.
    // Another case might happen if two different submit rules emit the same label
    // name. In such cases, we need to merge these entries and return a single submit
    // requirement result. If both entries agree in their status, return any of them.
    // Otherwise, favour the entry that is blocking submission.
    ImmutableMap.Builder<SubmitRequirement, SubmitRequirementResult> result =
        ImmutableMap.builder();
    for (Map.Entry<String, List<SubmitRequirementResult>> entry : srsByName.entrySet()) {
      if (entry.getValue().size() == 1) {
        SubmitRequirementResult srResult = entry.getValue().iterator().next();
        result.put(srResult.submitRequirement(), srResult);
        continue;
      }
      // If all submit requirements with the same name match in status, return the first one.
      List<SubmitRequirementResult> resultsSameName = entry.getValue();
      boolean allNonBlocking = resultsSameName.stream().allMatch(sr -> sr.fulfilled());
      if (allNonBlocking) {
        result.put(resultsSameName.get(0).submitRequirement(), resultsSameName.get(0));
      } else {
        // Otherwise, return the first submit requirement result that is blocking submission.
        Optional<SubmitRequirementResult> nonFulfilled =
            resultsSameName.stream().filter(sr -> !sr.fulfilled()).findFirst();
        if (nonFulfilled.isPresent()) {
          result.put(nonFulfilled.get().submitRequirement(), nonFulfilled.get());
        }
      }
    }
    return result.build();
  }

  static List<SubmitRequirementResult> createResult(
      SubmitRecord record, List<LabelType> labelTypes, ObjectId psCommitId, boolean isForced) {
    List<SubmitRequirementResult> results;
    if (record.ruleName != null && record.ruleName.equals(DefaultSubmitRule.RULE_NAME)) {
      results = createFromDefaultSubmitRecord(record.labels, labelTypes, psCommitId, isForced);
    } else {
      results = createFromCustomSubmitRecord(record, psCommitId, isForced);
    }
    logger.atFine().log("Converted submit record %s to submit requirements %s", record, results);
    return results;
  }

  private static List<SubmitRequirementResult> createFromDefaultSubmitRecord(
      @Nullable List<Label> labels,
      List<LabelType> labelTypes,
      ObjectId psCommitId,
      boolean isForced) {
    ImmutableList.Builder<SubmitRequirementResult> result = ImmutableList.builder();
    if (labels == null) {
      return result.build();
    }
    for (Label label : labels) {
      if (skipSubmitRequirementFor(label)) {
        continue;
      }
      Optional<LabelType> maybeLabelType = getLabelType(labelTypes, label.label);
      if (!maybeLabelType.isPresent()) {
        // Label type might have been removed from the project config. We don't have information
        // if it was blocking or not, hence we skip the label.
        continue;
      }
      LabelType labelType = maybeLabelType.get();
      if (!isBlocking(labelType)) {
        continue;
      }
      ImmutableList<String> atoms = toExpressionAtomList(labelType);
      SubmitRequirement.Builder req =
          SubmitRequirement.builder()
              .setName(label.label)
              .setSubmittabilityExpression(toExpression(atoms))
              .setAllowOverrideInChildProjects(labelType.isCanOverride());
      result.add(
          SubmitRequirementResult.builder()
              .legacy(Optional.of(true))
              .submitRequirement(req.build())
              .submittabilityExpressionResult(
                  createExpressionResult(toExpression(atoms), mapStatus(label), atoms))
              .patchSetCommitId(psCommitId)
              .forced(Optional.of(isForced))
              .build());
    }
    return result.build();
  }

  private static List<SubmitRequirementResult> createFromCustomSubmitRecord(
      SubmitRecord record, ObjectId psCommitId, boolean isForced) {
    String ruleName = record.ruleName != null ? record.ruleName : "Custom-Rule";
    if (record.labels == null || record.labels.isEmpty()) {
      SubmitRequirement sr =
          SubmitRequirement.builder()
              .setName(ruleName)
              .setSubmittabilityExpression(
                  SubmitRequirementExpression.create(String.format("rule:%s", ruleName)))
              .setAllowOverrideInChildProjects(false)
              .build();
      return ImmutableList.of(
          SubmitRequirementResult.builder()
              .legacy(Optional.of(true))
              .submitRequirement(sr)
              .submittabilityExpressionResult(
                  createExpressionResult(
                      sr.submittabilityExpression(),
                      mapStatus(record),
                      ImmutableList.of(ruleName),
                      record.errorMessage))
              .patchSetCommitId(psCommitId)
              .forced(Optional.of(isForced))
              .build());
    }
    ImmutableList.Builder<SubmitRequirementResult> result = ImmutableList.builder();
    for (Label label : record.labels) {
      if (skipSubmitRequirementFor(label)) {
        continue;
      }
      String expressionString = String.format("label:%s=%s", label.label, ruleName);
      SubmitRequirement sr =
          SubmitRequirement.builder()
              .setName(label.label)
              .setSubmittabilityExpression(SubmitRequirementExpression.create(expressionString))
              .setAllowOverrideInChildProjects(false)
              .build();
      result.add(
          SubmitRequirementResult.builder()
              .legacy(Optional.of(true))
              .submitRequirement(sr)
              .submittabilityExpressionResult(
                  createExpressionResult(
                      sr.submittabilityExpression(),
                      mapStatus(label),
                      ImmutableList.of(expressionString)))
              .patchSetCommitId(psCommitId)
              .build());
    }
    return result.build();
  }

  private static boolean isBlocking(LabelType labelType) {
    return labelType.getFunction().isBlock() || labelType.getFunction().isRequired();
  }

  private static SubmitRequirementExpression toExpression(List<String> atoms) {
    return SubmitRequirementExpression.create(String.join(" ", atoms));
  }

  private static ImmutableList<String> toExpressionAtomList(LabelType lt) {
    String ignoreSelfApproval =
        lt.isIgnoreSelfApproval() ? ",user=" + ChangeQueryBuilder.ARG_ID_NON_UPLOADER : "";
    switch (lt.getFunction()) {
      case MAX_WITH_BLOCK:
        return ImmutableList.of(
            String.format("label:%s=MAX", lt.getName()) + ignoreSelfApproval,
            String.format("-label:%s=MIN", lt.getName()));
      case ANY_WITH_BLOCK:
        return ImmutableList.of(String.format(String.format("-label:%s=MIN", lt.getName())));
      case MAX_NO_BLOCK:
        return ImmutableList.of(
            String.format(String.format("label:%s=MAX", lt.getName())) + ignoreSelfApproval);
      case NO_BLOCK:
      case NO_OP:
      case PATCH_SET_LOCK:
      default:
        return ImmutableList.of();
    }
  }

  private static Status mapStatus(Label label) {
    SubmitRequirementExpressionResult.Status status = Status.PASS;
    switch (label.status) {
      case OK:
      case MAY:
        status = Status.PASS;
        break;
      case REJECT:
      case NEED:
      case IMPOSSIBLE:
        status = Status.FAIL;
        break;
    }
    return status;
  }

  private static Status mapStatus(SubmitRecord submitRecord) {
    switch (submitRecord.status) {
      case OK:
      case CLOSED:
      case FORCED:
        return Status.PASS;
      case NOT_READY:
        return Status.FAIL;
      case RULE_ERROR:
      default:
        return Status.ERROR;
    }
  }

  private static SubmitRequirementExpressionResult createExpressionResult(
      SubmitRequirementExpression expression, Status status, ImmutableList<String> atoms) {
    return SubmitRequirementExpressionResult.create(
        expression,
        status,
        status == Status.PASS ? atoms : ImmutableList.of(),
        status == Status.FAIL ? atoms : ImmutableList.of());
  }

  private static SubmitRequirementExpressionResult createExpressionResult(
      SubmitRequirementExpression expression,
      Status status,
      ImmutableList<String> atoms,
      String errorMessage) {
    return SubmitRequirementExpressionResult.create(
        expression,
        status,
        status == Status.PASS ? atoms : ImmutableList.of(),
        status == Status.FAIL ? atoms : ImmutableList.of(),
        Optional.ofNullable(Strings.emptyToNull(errorMessage)));
  }

  private static Optional<LabelType> getLabelType(List<LabelType> labelTypes, String labelName) {
    List<LabelType> label =
        labelTypes.stream()
            .filter(lt -> lt.getName().equals(labelName))
            .collect(Collectors.toList());
    if (label.isEmpty()) {
      // Label might have been removed from the project.
      logger.atFine().log("Label '%s' was not found for the project.", labelName);
      return Optional.empty();
    } else if (label.size() > 1) {
      logger.atWarning().log("Found more than one label definition for label name '%s'", labelName);
      return Optional.empty();
    }
    return Optional.of(label.get(0));
  }

  /**
   * Returns true if we should skip creating a "submit requirement" result out of the "submit
   * record" label.
   */
  private static boolean skipSubmitRequirementFor(SubmitRecord.Label label) {
    return label.status == SubmitRecord.Label.Status.MAY;
  }
}
