// 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.owners.common;

import static com.googlesource.gerrit.owners.common.StreamUtils.iteratorStream;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.google.gerrit.entities.Account.Id;
import java.io.IOException;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ConfigurationParser {
  private static final Logger log = LoggerFactory.getLogger(OwnersConfig.class);
  private Accounts accounts;

  public ConfigurationParser(Accounts accounts) {
    this.accounts = accounts;
  }

  public OwnersConfig getOwnersConfig(byte[] yamlBytes) throws IOException {
    final OwnersConfig ret = new OwnersConfig();
    JsonNode jsonNode = new ObjectMapper(new YAMLFactory()).readValue(yamlBytes, JsonNode.class);
    Boolean inherited =
        Optional.ofNullable(jsonNode.get("inherited")).map(JsonNode::asBoolean).orElse(true);
    ret.setInherited(inherited);
    ret.setLabel(
        Optional.ofNullable(jsonNode.get("label"))
            .map(JsonNode::asText)
            .flatMap(LabelDefinition::parse));
    addClassicMatcher(jsonNode, ret);
    addMatchers(jsonNode, ret);
    return ret;
  }

  private void addClassicMatcher(JsonNode jsonNode, OwnersConfig ret) {
    ret.setOwners(toClassicOwnersList(jsonNode, "owners").collect(Collectors.toSet()));
    ret.setReviewers(toClassicOwnersList(jsonNode, "reviewers").collect(Collectors.toSet()));
  }

  private void addMatchers(JsonNode jsonNode, OwnersConfig ret) {
    getNode(jsonNode, "matchers")
        .map(m -> getMatchers(m))
        .ifPresent(m -> m.forEach(ret::addMatcher));
  }

  private Stream<Matcher> getMatchers(JsonNode node) {
    return iteratorStream(node.iterator())
        .map(this::toMatcher)
        .filter(Optional::isPresent)
        .map(m -> m.get());
  }

  private static Stream<String> extractAsText(JsonNode node) {
    if (node.isTextual()) {
      return Stream.of(node.asText());
    }
    return iteratorStream(node.iterator()).map(JsonNode::asText);
  }

  private static <T> Stream<T> flatten(Optional<Stream<T>> optionalStream) {
    return optionalStream.orElse(Stream.empty());
  }

  private Stream<String> toClassicOwnersList(JsonNode jsonNode, String sectionName) {
    Stream<String> ownersStream =
        Optional.ofNullable(jsonNode.get(sectionName))
            .map(ConfigurationParser::extractAsText)
            .orElse(Stream.empty());
    return ownersStream;
  }

  private Optional<Matcher> toMatcher(JsonNode node) {
    Set<Id> owners =
        getNode(node, "owners")
            .map(ConfigurationParser::extractAsText)
            .orElse(Stream.empty())
            .flatMap(o -> accounts.find(o).stream())
            .collect(Collectors.toSet());
    Set<String> groupOwners =
        flatten(
                getNode(node, "owners")
                    .map(ConfigurationParser::extractAsText)
                    .map(owns -> owns.map(PathOwnersEntry::stripOwnerDomain)))
            .collect(Collectors.toSet());
    Set<Id> reviewers =
        getNode(node, "reviewers")
            .map(ConfigurationParser::extractAsText)
            .orElse(Stream.empty())
            .flatMap(o -> accounts.find(o).stream())
            .collect(Collectors.toSet());

    Optional<Matcher> suffixMatcher =
        getText(node, "suffix").map(el -> new SuffixMatcher(el, owners, reviewers, groupOwners));
    Optional<Matcher> regexMatcher =
        getText(node, "regex").map(el -> new RegExMatcher(el, owners, reviewers, groupOwners));
    Optional<Matcher> partialRegexMatcher =
        getText(node, "partial_regex")
            .map(el -> new PartialRegExMatcher(el, owners, reviewers, groupOwners));
    Optional<Matcher> exactMatcher =
        getText(node, "exact").map(el -> new ExactMatcher(el, owners, reviewers, groupOwners));
    Optional<Matcher> genericMatcher =
        getText(node, "generic").map(el -> new GenericMatcher(el, owners, reviewers, groupOwners));

    return Optional.ofNullable(
        suffixMatcher.orElseGet(
            () ->
                regexMatcher.orElseGet(
                    () ->
                        partialRegexMatcher.orElseGet(
                            () ->
                                exactMatcher.orElseGet(
                                    () ->
                                        genericMatcher.orElseGet(
                                            () -> {
                                              log.warn(
                                                  "Ignoring invalid element " + node.toString());
                                              return null;
                                            }))))));
  }

  private static Optional<String> getText(JsonNode node, String field) {
    return Optional.ofNullable(node.get(field)).map(JsonNode::asText);
  }

  private static Optional<JsonNode> getNode(JsonNode node, String field) {
    return Optional.ofNullable(node.get(field));
  }
}
