package com.google.sps.utilities;

import com.google.common.collect.Sets;
import com.google.sps.data.Event;
import com.google.sps.data.User;
import com.google.sps.data.VolunteeringOpportunity;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import org.javatuples.Pair;

public class EventRanker {
  private static final Double SIMILAR_WEIGHT = 0.7;
  private static final Double NO_MATCH_WEIGHT = 0.0;

  /**
   * Sorts events based on each event's score. Breaks ties with the event's date; the more recent
   * event will be ranked higher. Makes the assumption that all events are NOT in the past.
   *
   * @param user The user for whom the events are ranked
   * @param directMatches A {@link Set} of events that need to be ranked; direct event maches
   * @param similarMatches A {@link Set} of events that need to be ranked; similar event matches
   * @return A {@link List} of events that is ranked according to each element's score
   */
  public static List<Event> rankEvents(User user, Set<Event> events) {
    Map<Event, Double> eventScoreMap = getEventScoreMap(user, events);
    List<Event> rankedEvents = new ArrayList<>(eventScoreMap.keySet());
    Collections.sort(
        rankedEvents,
        (Event event1, Event event2) -> {
          int comparison = eventScoreMap.get(event1).compareTo(eventScoreMap.get(event2));
          if (comparison == 0) {
            comparison = event2.getDate().compareTo(event1.getDate());
          }
          return comparison;
        });
    Collections.reverse(rankedEvents);
    return rankedEvents;
  }

  private static Map<Event, Double> getEventScoreMap(User user, Set<Event> events) {
    Pair<Set<Pair<Event, Integer>>, Set<Pair<Event, Integer>>> allEvents =
        new GetLabelCategories().getEventRelevancy(events, user);
    Set<Pair<Event, Integer>> directEventPairs = allEvents.getValue0();
    Set<Pair<Event, Integer>> similarEventPairs = allEvents.getValue1();

    Set<Event> directEvents = new HashSet<>();
    Set<Event> similarEvents = new HashSet<>();
    Set<Event> noMatchEvents = new HashSet<>(events);

    Map<Event, Double> eventScoreMap = new HashMap<>();
    for (Pair<Event, Integer> eventRelevancyPair : directEventPairs) {
      Event directEvent = eventRelevancyPair.getValue0();
      eventScoreMap.put(directEvent, new Double(eventRelevancyPair.getValue1()));
      directEvents.add(directEvent);
    }
    for (Pair<Event, Integer> eventRelevancyPair : similarEventPairs) {
      Event similarEvent = eventRelevancyPair.getValue0();
      eventScoreMap.put(eventRelevancyPair.getValue0(), SIMILAR_WEIGHT * eventRelevancyPair.getValue1());
      similarEvents.add(similarEvent);
    }
    noMatchEvents.removeAll(directEvents);
    noMatchEvents.removeAll(similarEvents);
    for (Event event : noMatchEvents) {
      eventScoreMap.put(event, NO_MATCH_WEIGHT);
    }
    return eventScoreMap;
  }
}

@@ -491,16 +491,67 @@
 anker %7B%0A
+  private static final Double DIRECT_WEIGHT = 1.0;%0A
   privat
@@ -2041,125 +2041,229 @@
     
-Set%3CPair%3CEvent, Integer%3E%3E directEventPairs = allEvents.getValue0();%0A    Set%3CPair%3CEvent, Integer%3E%3E similarEventPairs =
+Map%3CEvent, Double%3E eventScoreMap = new HashMap%3C%3E();%0A    Set%3CEvent%3E directEvents = processEventMatches(eventScoreMap, allEvents.getValue0(), DIRECT_WEIGHT);%0A    Set%3CEvent%3E similarEvents = processEventMatches(eventScoreMap,
  all
@@ -2284,72 +2284,88 @@
 e1()
+, SIMILAR_WEIGHT)
 ;%0A
-%0A    Set%3CEvent%3E directEvents = new HashSet%3C%3E();%0A    Set%3C
+    for (Event event : getNoMatchEvents(events, direct
 Event
-%3E
+s,
  sim
@@ -2378,119 +2378,310 @@
 ents
- = new HashSet%3C%3E();%0A    Set%3CEvent%3E noMatchEvents = new HashSet%3C%3E(events);%0A%0A    Map%3CEvent, Double%3E eventScoreMap
+)) %7B%0A      eventScoreMap.put(event, NO_MATCH_WEIGHT);%0A    %7D%0A    System.out.println(eventScoreMap.size());%0A    return eventScoreMap;%0A  %7D%0A%0A  private static Set%3CEvent%3E processEventMatches(%0A      Map%3CEvent, Double%3E eventScoreMap, Set%3CPair%3CEvent, Integer%3E%3E eventPairs, Double weight) %7B%0A    Set%3CEvent%3E events
  = n
@@ -2679,35 +2679,35 @@
 vents = new Hash
-Map
+Set
 %3C%3E();%0A    for (P
@@ -2747,23 +2747,17 @@
 yPair : 
-directE
+e
 ventPair
@@ -2773,23 +2773,17 @@
   Event 
-directE
+e
 vent = e
@@ -2841,32 +2841,24 @@
 put(
-directEvent, new Double(
+event, weight * 
 even
@@ -2884,25 +2884,24 @@
 alue1())
-)
 ;%0A      
 directEv
@@ -2892,23 +2892,17 @@
 ;%0A      
-directE
+e
 vents.ad
@@ -2903,23 +2903,17 @@
 nts.add(
-directE
+e
 vent);%0A 
@@ -2925,286 +2925,199 @@
     
-for (Pair%3CEvent, Integer%3E eventRelevancyPair : similarEventPairs) %7B%0A      Event similarEvent = eventRelevancyPair.getValue0();%0A      eventScoreMap.put(eventRelevancyPair.getValue0(), SIMILAR_WEIGHT * eventRelevancyPair.getValue1());%0A      similarEvents.add(similarE
+return events;%0A  %7D%0A%0A  private static Set%3CEvent%3E getNoMatchEvents(Set%3CEvent%3E events, Set%3CEvent%3E directEvents, Set%3CEvent%3E similarEvents) %7B%0A    Set%3CEvent%3E noMatchEvents = new HashSet%3C%3E(e
 vent
+s
 );%0A
-    %7D%0A
     
@@ -3207,123 +3207,28 @@
     
-for (Event event : noMatchEvents) %7B%0A      eventScoreMap.put(event, NO_MATCH_WEIGHT);%0A    %7D%0A    return eventScoreMap
+return noMatchEvents
 ;%0A  

Break out EventRanker functions