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

import static com.google.common.collect.ImmutableList.toImmutableList;
import static java.util.Arrays.stream;
import static java.util.stream.Collectors.groupingBy;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.gerrit.common.Nullable;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * Gets the differences between two {@link ChangeInfo}s.
 *
 * <p>This must be in package {@code com.google.gerrit.extensions.common} for access to protected
 * constructors.
 *
 * <p>This assumes that every class reachable from {@link ChangeInfo} has a non-private constructor
 * with zero parameters and overrides the equals method.
 */
public final class ChangeInfoDiffer {

  /**
   * Returns the difference between two instances of {@link ChangeInfo}.
   *
   * <p>The {@link ChangeInfoDifference} returned has the following properties:
   *
   * <p>Unrepeated fields are present in the difference returned when they differ between {@code
   * oldChangeInfo} and {@code newChangeInfo}. When there's an unrepeated field that's not a {@link
   * String}, primitive, or enum, its fields are only returned when they differ.
   *
   * <p>Entries in {@link Map} fields are returned when a key is present in {@code newChangeInfo}
   * and not {@code oldChangeInfo}. If a key is present in both, the diff of the value is returned.
   *
   * <p>{@link Collection} fields in {@link ChangeInfoDifference#added()} contain only items found
   * in {@code newChangeInfo} and not {@code oldChangeInfo}.
   *
   * <p>{@link Collection} fields in {@link ChangeInfoDifference#removed()} contain only items found
   * in {@code oldChangeInfo} and not {@code newChangeInfo}.
   *
   * @param oldChangeInfo the previous {@link ChangeInfo} to diff against {@code newChangeInfo}
   * @param newChangeInfo the {@link ChangeInfo} to diff against {@code oldChangeInfo}
   * @return the difference between the given {@link ChangeInfo}s
   */
  public static ChangeInfoDifference getDifference(
      ChangeInfo oldChangeInfo, ChangeInfo newChangeInfo) {
    return ChangeInfoDifference.builder()
        .setOldChangeInfo(oldChangeInfo)
        .setNewChangeInfo(newChangeInfo)
        .setAdded(getAdded(oldChangeInfo, newChangeInfo))
        .setRemoved(getAdded(newChangeInfo, oldChangeInfo))
        .build();
  }

  @SuppressWarnings("unchecked") // reflection is used to construct instances of T
  private static <T> T getAdded(T oldValue, T newValue) {
    if (newValue instanceof Collection) {
      List<?> result = getAddedForCollection((Collection<?>) oldValue, (Collection<?>) newValue);
      return (T) result;
    }

    if (newValue instanceof Map) {
      Map<?, ?> result = getAddedForMap((Map<?, ?>) oldValue, (Map<?, ?>) newValue);
      return (T) result;
    }

    T toPopulate = (T) construct(newValue.getClass());
    if (toPopulate == null) {
      return null;
    }

    for (Field field : newValue.getClass().getDeclaredFields()) {
      if (java.lang.reflect.Modifier.isStatic(field.getModifiers())) {
        continue;
      }

      Object newFieldObj = get(field, newValue);
      if (oldValue == null || newFieldObj == null) {
        set(field, toPopulate, newFieldObj);
        continue;
      }

      Object oldFieldObj = get(field, oldValue);
      if (newFieldObj.equals(oldFieldObj)) {
        continue;
      }

      if (isSimple(field.getType()) || oldFieldObj == null) {
        set(field, toPopulate, newFieldObj);
      } else if (newFieldObj instanceof Collection || newFieldObj instanceof Map) {
        set(field, toPopulate, getAdded(oldFieldObj, newFieldObj));
      } else {
        // Recurse to set all fields in the non-primitive object.
        set(field, toPopulate, getAdded(oldFieldObj, newFieldObj));
      }
    }
    return toPopulate;
  }

  @VisibleForTesting
  static boolean isSimple(Class<?> c) {
    return c.isPrimitive()
        || c.isEnum()
        || String.class.isAssignableFrom(c)
        || Number.class.isAssignableFrom(c)
        || Boolean.class.isAssignableFrom(c)
        || Timestamp.class.isAssignableFrom(c);
  }

  @VisibleForTesting
  static Object construct(Class<?> c) {
    // Only use constructors without parameters because we can't determine what values to pass.
    return stream(c.getDeclaredConstructors())
        .filter(constructor -> constructor.getParameterCount() == 0)
        .findAny()
        .map(ChangeInfoDiffer::construct)
        .orElseThrow(
            () ->
                new IllegalStateException("Class " + c + " must have a zero argument constructor"));
  }

  private static Object construct(Constructor<?> constructor) {
    try {
      return constructor.newInstance();
    } catch (ReflectiveOperationException e) {
      throw new IllegalStateException("Failed to construct class " + constructor.getName(), e);
    }
  }

  /** Returns {@code null} if nothing has been added to {@code oldCollection} */
  @Nullable
  private static ImmutableList<?> getAddedForCollection(
      Collection<?> oldCollection, Collection<?> newCollection) {
    ImmutableList<?> notInOldCollection = getAdditions(oldCollection, newCollection);
    return notInOldCollection.isEmpty() ? null : notInOldCollection;
  }

  @Nullable
  private static ImmutableList<Object> getAdditions(
      Collection<?> oldCollection, Collection<?> newCollection) {
    if (oldCollection == null)
      return newCollection != null ? ImmutableList.copyOf(newCollection) : null;

    Map<Object, List<Object>> duplicatesMap = newCollection.stream().collect(groupingBy(v -> v));
    oldCollection.forEach(
        v -> {
          if (duplicatesMap.containsKey(v)) {
            duplicatesMap.get(v).remove(v);
          }
        });
    return duplicatesMap.values().stream().flatMap(Collection::stream).collect(toImmutableList());
  }

  /** Returns {@code null} if nothing has been added to {@code oldMap} */
  @Nullable
  private static ImmutableMap<Object, Object> getAddedForMap(Map<?, ?> oldMap, Map<?, ?> newMap) {
    ImmutableMap.Builder<Object, Object> additionsBuilder = ImmutableMap.builder();
    for (Map.Entry<?, ?> entry : newMap.entrySet()) {
      Object added = getAdded(oldMap.get(entry.getKey()), entry.getValue());
      if (added != null) {
        additionsBuilder.put(entry.getKey(), added);
      }
    }
    ImmutableMap<Object, Object> additions = additionsBuilder.build();
    return additions.isEmpty() ? null : additions;
  }

  private static Object get(Field field, Object obj) {
    try {
      return field.get(obj);
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(
          String.format("Access denied getting field %s in %s", field.getName(), obj.getClass()),
          e);
    }
  }

  private static void set(Field field, Object obj, Object value) {
    try {
      field.set(obj, value);
    } catch (IllegalAccessException e) {
      throw new IllegalStateException(
          String.format(
              "Access denied setting field %s in %s", field.getName(), obj.getClass().getName()),
          e);
    }
  }

  private ChangeInfoDiffer() {}
}
