package com.kickstarter.ui.adapters;

import android.util.Pair;
import android.view.View;

import com.kickstarter.R;
import com.kickstarter.models.Category;
import com.kickstarter.services.DiscoveryParams;
import com.kickstarter.ui.DiscoveryFilterStyle;
import com.kickstarter.ui.viewholders.DiscoveryFilterDividerViewHolder;
import com.kickstarter.ui.viewholders.DiscoveryFilterViewHolder;
import com.kickstarter.ui.viewholders.KsrViewHolder;

import java.util.Collections;
import java.util.List;

import rx.Observable;

public class DiscoveryFilterAdapter extends KsrAdapter {
  private final Delegate delegate;
  private DiscoveryParams selectedDiscoveryParams;

  public interface Delegate extends DiscoveryFilterViewHolder.Delegate {}

  public DiscoveryFilterAdapter(final Delegate delegate, final DiscoveryParams selectedDiscoveryParams) {
    this.delegate = delegate;
    this.selectedDiscoveryParams = selectedDiscoveryParams;
  }

  protected int layout(final SectionRow sectionRow) {
    if (sectionRow.section() == 1) {
      return R.layout.discovery_filter_divider_view;
    }
    return R.layout.discovery_filter_view;
  }

  protected KsrViewHolder viewHolder(final int layout, final View view) {
    if (layout == R.layout.discovery_filter_divider_view) {
      return new DiscoveryFilterDividerViewHolder(view);
    }
    return new DiscoveryFilterViewHolder(view, delegate);
  }

  public void takeCategories(final List<Category> initialCategories) {
    data().clear();

    Observable<List<Pair<DiscoveryParams, DiscoveryFilterStyle>>> sections = categoryDiscoveryParams(initialCategories)
      .startWith(filterDiscoveryParams())
      .map(paramsList -> {
        return Observable.from(paramsList).map(p -> {
          return Pair.create(p, new DiscoveryFilterStyle.Builder().build());
        }).toList().toBlocking().single();
      });

    sections.subscribe(s -> data().add(s)).unsubscribe();
    data().add(1, Collections.singletonList(null)); // Category divider

    notifyDataSetChanged();
  }

  protected Observable<List<DiscoveryParams>> filterDiscoveryParams() {
    return Observable.just(
      new DiscoveryParams.Builder().staffPicks(true).build(),
      new DiscoveryParams.Builder().starred(1).build(),
      new DiscoveryParams.Builder().build() // Everything sort
    ).toList();
  }

  protected Observable<List<DiscoveryParams>> categoryDiscoveryParams(final List<Category> initialCategories) {
    final Observable<Category> categories = Observable.from(initialCategories);
    final Observable<Category> rootCategories = categories.filter(Category::isRoot);

    /* Insert duplicate root categories. The duplicate will be used as a nested row under the root downstream, e.g.:
     * Art
     *  - All of Art
     */
    final Observable<DiscoveryParams> params = categories.concatWith(rootCategories)
      .map(c -> new DiscoveryParams.Builder().category(c).build())
      .toSortedList((p1, p2) -> p1.category().discoveryFilterCompareTo(p2.category()))
      .flatMap(Observable::from);

    final Observable<List<DiscoveryParams>> groupedParams = params
      .groupBy(p -> p.category().rootId())
      .map(Observable::toList)
      .flatMap(l -> l);

    return groupedParams;
  }
}

@@ -1493,80 +1493,448 @@
     
-Observable%3CList%3CPair%3CDiscoveryParams, DiscoveryFilterStyle%3E%3E%3E sections =
+discoveryParamsSections(initialCategories)%0A      .subscribe(s -%3E data().add(s)).unsubscribe();%0A%0A    data().add(1, Collections.singletonList(null)); // Category divider%0A%0A    notifyDataSetChanged();%0A  %7D%0A%0A  /**%0A   * Returns an Observable where each item is a list of params/style pairs.%0A   */%0A  protected Observable%3CList%3CPair%3CDiscoveryParams, DiscoveryFilterStyle%3E%3E%3E discoveryParamsSections(final List%3CCategory%3E initialCategories) %7B%0A    return
  cat
@@ -2230,172 +2230,68 @@
 %7D);%0A
-%0A
   
-  sections.subscribe(s -%3E data().add(s)).unsubscribe();%0A    data().add(1, Collections.singletonList(null)); // Category divider%0A%0A    notifyDataSetChanged();%0A  %7D%0A
+%7D%0A%0A  /**%0A   * Params for the top section of filters.%0A   */
 %0A  p
@@ -2355,24 +2355,55 @@
 yParams() %7B%0A
+    // TODO: Add social filter%0A
     return O
@@ -2598,12 +2598,14 @@
 ing 
-sort
+filter
 %0A   
@@ -2618,24 +2618,278 @@
 ist();%0A  %7D%0A%0A
+  /**%0A   * Transforms a list of categories into an Observable list of params.%0A   *%0A   * Each list of params has a duplicate root category. The duplicate will be used as a nested row under the%0A   * root downstream, e.g.:%0A   * Art%0A   *  - All of Art%0A   */%0A
   protected 
@@ -3158,165 +3158,8 @@
 );%0A%0A
-    /* Insert duplicate root categories. The duplicate will be used as a nested row under the root downstream, e.g.:%0A     * Art%0A     *  - All of Art%0A     */%0A
     
@@ -3436,77 +3436,21 @@
     
-final Observable%3CList%3CDiscoveryParams%3E%3E groupedParams = params%0A      
+return params
 .gro
@@ -3540,35 +3540,8 @@
  l);
-%0A%0A    return groupedParams;
 %0A  %7D

Move building up of observables into separate methods