package com.morihacky.android.rxjava.fragments;

import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.Nullable;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;

import com.jakewharton.rxbinding2.widget.RxTextView;
import com.jakewharton.rxbinding2.widget.TextViewTextChangeEvent;
import com.morihacky.android.rxjava.R;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import butterknife.Unbinder;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.observers.DisposableObserver;
import timber.log.Timber;

import static co.kaush.core.util.CoreNullnessUtils.isNotNullOrEmpty;
import static java.lang.String.format;

public class DebounceSearchEmitterFragment extends BaseFragment {

  @BindView(R.id.list_threading_log)
  ListView _logsList;

  @BindView(R.id.input_txt_debounce)
  EditText _inputSearchText;

  private LogAdapter _adapter;
  private List<String> _logs;

  private Disposable _disposable;
  private Unbinder unbinder;

  @Override
  public void onDestroy() {
    super.onDestroy();
    _disposable.dispose();
    unbinder.unbind();
  }

  @Override
  public View onCreateView(
      LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
    View layout = inflater.inflate(R.layout.fragment_debounce, container, false);
    unbinder = ButterKnife.bind(this, layout);
    return layout;
  }

  @OnClick(R.id.clr_debounce)
  public void onClearLog() {
    _logs = new ArrayList<>();
    _adapter.clear();
  }

  @Override
  public void onActivityCreated(@Nullable Bundle savedInstanceState) {

    super.onActivityCreated(savedInstanceState);
    _setupLogger();

    _disposable =
        RxTextView.textChangeEvents(_inputSearchText)
            .debounce(400, TimeUnit.MILLISECONDS) // default Scheduler is Computation
            .filter(changes -> isNotNullOrEmpty(changes.text().toString()))
            .observeOn(AndroidSchedulers.mainThread())
            .subscribeWith(_getSearchObserver());
  }

  // -----------------------------------------------------------------------------------
  // Main Rx entities

  private DisposableObserver<TextViewTextChangeEvent> _getSearchObserver() {
    return new DisposableObserver<TextViewTextChangeEvent>() {
      @Override
      public void onComplete() {
        Timber.d("--------- onComplete");
      }

      @Override
      public void onError(Throwable e) {
        Timber.e(e, "--------- Woops on error!");
        _log("Dang error. check your logs");
      }

      @Override
      public void onNext(TextViewTextChangeEvent onTextChangeEvent) {
        _log(format("Searching for %s", onTextChangeEvent.text().toString()));
      }
    };
  }

  // -----------------------------------------------------------------------------------
  // Method that help wiring up the example (irrelevant to RxJava)

  private void _setupLogger() {
    _logs = new ArrayList<>();
    _adapter = new LogAdapter(getActivity(), new ArrayList<>());
    _logsList.setAdapter(_adapter);
  }

  private void _log(String logMsg) {

    if (_isCurrentlyOnMainThread()) {
      _logs.add(0, logMsg + " (main thread) ");
      _adapter.clear();
      _adapter.addAll(_logs);
    } else {
      _logs.add(0, logMsg + " (NOT main thread) ");

      // You can only do below stuff on main thread.
      new Handler(Looper.getMainLooper())
          .post(
              () -> {
                _adapter.clear();
                _adapter.addAll(_logs);
              });
    }
  }

  private boolean _isCurrentlyOnMainThread() {
    return Looper.myLooper() == Looper.getMainLooper();
  }

  private class LogAdapter extends ArrayAdapter<String> {

    public LogAdapter(Context context, List<String> logs) {
      super(context, R.layout.item_log, R.id.item_log, logs);
    }
  }
}