package com.prateekj.snooper.espresso;

import android.support.annotation.NonNull;
import android.support.test.espresso.PerformException;
import android.support.test.espresso.UiController;
import android.support.test.espresso.ViewAction;
import android.support.test.espresso.util.HumanReadables;
import android.view.View;

import org.hamcrest.CustomTypeSafeMatcher;
import org.hamcrest.Matcher;

import static android.support.test.espresso.Espresso.registerIdlingResources;
import static android.support.test.espresso.Espresso.unregisterIdlingResources;
import static java.lang.String.format;

public class WaitForViewAction implements ViewAction {

  private Matcher<View> viewMatcher;
  private int timeout;

  public WaitForViewAction(Matcher<View> viewMatcher, int timeout) {
    this.viewMatcher = viewMatcher;
    this.timeout = timeout;
  }

  @Override
  public Matcher<View> getConstraints() {
    return anyView();
  }

  @Override
  public String getDescription() {
    return format("performing wait for until view matcher %s matches", viewMatcher.toString());
  }

  @Override
  public void perform(UiController uiController, View view) {
    ViewMatcherIdlingResource idlingResource = new ViewMatcherIdlingResource(timeout, viewMatcher, view);
    registerIdlingResources(idlingResource);
    uiController.loopMainThreadUntilIdle();
    unregisterIdlingResources(idlingResource);
    if(!idlingResource.isMatched()) {
      throw new PerformException.Builder()
        .withActionDescription(getDescription())
        .withViewDescription(HumanReadables.getViewHierarchyErrorMessage(view, null, "Action timed out : " + getDescription(), null))
        .build();
    }
  }

  @NonNull
  private CustomTypeSafeMatcher<View> anyView() {
    return new CustomTypeSafeMatcher<View>("") {
      @Override
      protected boolean matchesSafely(View item) {
        return true;
      }
    };
  }
}