/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you 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 org.apache.druid.sql.calcite.filtration;

import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Range;
import com.google.common.collect.RangeSet;
import org.apache.druid.java.util.common.ISE;
import org.apache.druid.query.filter.AndDimFilter;
import org.apache.druid.query.filter.BoundDimFilter;
import org.apache.druid.query.filter.DimFilter;
import org.apache.druid.query.filter.NotDimFilter;
import org.apache.druid.query.filter.OrDimFilter;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class CombineAndSimplifyBounds extends BottomUpTransform
{
  private static final CombineAndSimplifyBounds INSTANCE = new CombineAndSimplifyBounds();

  private CombineAndSimplifyBounds()
  {
  }

  public static CombineAndSimplifyBounds instance()
  {
    return INSTANCE;
  }

  @Override
  public DimFilter process(DimFilter filter)
  {
    if (filter instanceof AndDimFilter) {
      final List<DimFilter> children = getAndFilterChildren((AndDimFilter) filter);
      final DimFilter one = doSimplifyAnd(children);
      final DimFilter two = negate(doSimplifyOr(negateAll(children)));
      return computeCost(one) <= computeCost(two) ? one : two;
    } else if (filter instanceof OrDimFilter) {
      final List<DimFilter> children = getOrFilterChildren((OrDimFilter) filter);
      final DimFilter one = doSimplifyOr(children);
      final DimFilter two = negate(doSimplifyAnd(negateAll(children)));
      return computeCost(one) <= computeCost(two) ? one : two;
    } else if (filter instanceof NotDimFilter) {
      final DimFilter field = ((NotDimFilter) filter).getField();
      final DimFilter candidate;
      if (field instanceof OrDimFilter) {
        candidate = doSimplifyAnd(negateAll(getOrFilterChildren((OrDimFilter) field)));
      } else if (field instanceof AndDimFilter) {
        candidate = doSimplifyOr(negateAll(getAndFilterChildren((AndDimFilter) field)));
      } else {
        candidate = negate(field);
      }
      return computeCost(filter) <= computeCost(candidate) ? filter : candidate;
    } else {
      return filter;
    }
  }

  private List<DimFilter> getAndFilterChildren(final AndDimFilter filter)
  {
    final List<DimFilter> children = new ArrayList<>();
    for (final DimFilter field : filter.getFields()) {
      if (field instanceof AndDimFilter) {
        children.addAll(getAndFilterChildren((AndDimFilter) field));
      } else {
        children.add(field);
      }
    }
    return children;
  }

  private List<DimFilter> getOrFilterChildren(final OrDimFilter filter)
  {
    final List<DimFilter> children = new ArrayList<>();
    for (final DimFilter field : filter.getFields()) {
      if (field instanceof OrDimFilter) {
        children.addAll(getOrFilterChildren((OrDimFilter) field));
      } else {
        children.add(field);
      }
    }
    return children;
  }

  private static DimFilter doSimplifyAnd(final List<DimFilter> children)
  {
    return doSimplify(children, false);
  }

  private static DimFilter doSimplifyOr(final List<DimFilter> children)
  {
    return doSimplify(children, true);
  }

  /**
   * Simplify BoundDimFilters that are children of an OR or an AND.
   *
   * @param children    the filters
   * @param disjunction true for OR, false for AND
   *
   * @return simplified filters
   */
  private static DimFilter doSimplify(final List<DimFilter> children, boolean disjunction)
  {
    // Copy the list of child filters. We'll modify the copy and eventually return it.
    final List<DimFilter> newChildren = Lists.newArrayList(children);

    // Group Bound filters by dimension, extractionFn, and comparator and compute a RangeSet for each one.
    final Map<BoundRefKey, List<BoundDimFilter>> bounds = new HashMap<>();

    for (final DimFilter child : newChildren) {
      if (child instanceof BoundDimFilter) {
        final BoundDimFilter bound = (BoundDimFilter) child;
        final BoundRefKey boundRefKey = BoundRefKey.from(bound);
        final List<BoundDimFilter> filterList = bounds.computeIfAbsent(boundRefKey, k -> new ArrayList<>());
        filterList.add(bound);
      }
    }

    // Try to simplify filters within each group.
    for (Map.Entry<BoundRefKey, List<BoundDimFilter>> entry : bounds.entrySet()) {
      final BoundRefKey boundRefKey = entry.getKey();
      final List<BoundDimFilter> filterList = entry.getValue();

      // Create a RangeSet for this group.
      final RangeSet<BoundValue> rangeSet = disjunction
                                            ? RangeSets.unionRanges(Bounds.toRanges(filterList))
                                            : RangeSets.intersectRanges(Bounds.toRanges(filterList));

      if (rangeSet.asRanges().size() < filterList.size()) {
        // We found a simplification. Remove the old filters and add new ones.
        for (final BoundDimFilter bound : filterList) {
          if (!newChildren.remove(bound)) {
            // Don't expect this to happen, but include it as a sanity check.
            throw new ISE("Tried to remove bound, but couldn't");
          }
        }

        if (rangeSet.asRanges().isEmpty()) {
          // range set matches nothing, equivalent to FALSE
          newChildren.add(Filtration.matchNothing());
        }

        for (final Range<BoundValue> range : rangeSet.asRanges()) {
          if (!range.hasLowerBound() && !range.hasUpperBound()) {
            // range matches all, equivalent to TRUE
            newChildren.add(Filtration.matchEverything());
          } else {
            newChildren.add(Bounds.toFilter(boundRefKey, range));
          }
        }
      }
    }

    // Finally: Go through newChildren, removing or potentially exiting early based on TRUE / FALSE marker filters.
    Preconditions.checkState(newChildren.size() > 0, "newChildren.size > 0");

    final Iterator<DimFilter> iterator = newChildren.iterator();
    while (iterator.hasNext()) {
      final DimFilter newChild = iterator.next();

      if (Filtration.matchNothing().equals(newChild)) {
        // Child matches nothing, equivalent to FALSE
        // OR with FALSE => ignore
        // AND with FALSE => always false, short circuit
        if (disjunction) {
          iterator.remove();
        } else {
          return Filtration.matchNothing();
        }
      } else if (Filtration.matchEverything().equals(newChild)) {
        // Child matches everything, equivalent to TRUE
        // OR with TRUE => always true, short circuit
        // AND with TRUE => ignore
        if (disjunction) {
          return Filtration.matchEverything();
        } else {
          iterator.remove();
        }
      }
    }

    if (newChildren.isEmpty()) {
      // If "newChildren" is empty at this point, it must have consisted entirely of TRUE / FALSE marker filters.
      if (disjunction) {
        // Must have been all FALSE filters (the only kind we would have removed above).
        return Filtration.matchNothing();
      } else {
        // Must have been all TRUE filters (the only kind we would have removed above).
        return Filtration.matchEverything();
      }
    } else if (newChildren.size() == 1) {
      return newChildren.get(0);
    } else {
      return disjunction ? new OrDimFilter(newChildren) : new AndDimFilter(newChildren);
    }
  }

  private static DimFilter negate(final DimFilter filter)
  {
    if (Filtration.matchEverything().equals(filter)) {
      return Filtration.matchNothing();
    } else if (Filtration.matchNothing().equals(filter)) {
      return Filtration.matchEverything();
    } else if (filter instanceof NotDimFilter) {
      return ((NotDimFilter) filter).getField();
    } else if (filter instanceof BoundDimFilter) {
      final BoundDimFilter negated = Bounds.not((BoundDimFilter) filter);
      return negated != null ? negated : new NotDimFilter(filter);
    } else {
      return new NotDimFilter(filter);
    }
  }

  private static List<DimFilter> negateAll(final List<DimFilter> children)
  {
    final List<DimFilter> newChildren = Lists.newArrayListWithCapacity(children.size());
    for (final DimFilter child : children) {
      newChildren.add(negate(child));
    }
    return newChildren;
  }

  private static int computeCost(final DimFilter filter)
  {
    if (filter instanceof NotDimFilter) {
      return computeCost(((NotDimFilter) filter).getField());
    } else if (filter instanceof AndDimFilter) {
      int cost = 0;
      for (DimFilter field : ((AndDimFilter) filter).getFields()) {
        cost += computeCost(field);
      }
      return cost;
    } else if (filter instanceof OrDimFilter) {
      int cost = 0;
      for (DimFilter field : ((OrDimFilter) filter).getFields()) {
        cost += computeCost(field);
      }
      return cost;
    } else {
      return 1;
    }
  }
}
