/**
 * Copyright (c) Facebook, Inc. and its affiliates.
 *
 * <p>This source code is licensed under the MIT license found in the LICENSE file in the root
 * directory of this source tree.
 */
package com.facebook.react.testing.idledetection;

import com.facebook.react.bridge.ReactContext;

public class ReactIdleDetectionUtil {

  /**
   * Waits for both the UI thread and bridge to be idle. It determines this by waiting for the
   * bridge to become idle, then waiting for the UI thread to become idle, then checking if the
   * bridge is idle again (if the bridge was idle before and is still idle after running the UI
   * thread to idle, then there are no more events to process in either place).
   *
   * <p>Also waits for any Choreographer callbacks to run after the initial sync since things like
   * UI events are initiated from Choreographer callbacks.
   */
  public static void waitForBridgeAndUIIdle(
      ReactBridgeIdleSignaler idleSignaler, final ReactContext reactContext, long timeoutMs) {

    return;
    // TODO: re-enable after cleanup of android-x migration
    //    UiThreadUtil.assertNotOnUiThread();
    //
    //    long startTime = SystemClock.uptimeMillis();
    //    waitInner(idleSignaler, timeoutMs);
    //
    //    long timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
    //    waitForChoreographer(timeToWait);
    //    waitForJSIdle(reactContext);
    //
    //    timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
    //    waitInner(idleSignaler, timeToWait);
    //    timeToWait = Math.max(1, timeoutMs - (SystemClock.uptimeMillis() - startTime));
    //    waitForChoreographer(timeToWait);
  }

  //  private static void waitForChoreographer(long timeToWait) {
  //    final int waitFrameCount = 2;
  //    final CountDownLatch latch = new CountDownLatch(1);
  //    UiThreadUtil.runOnUiThread(
  //        new Runnable() {
  //          @Override
  //          public void run() {
  //            final ChoreographerCompat choreographerCompat = ChoreographerCompat.getInstance();
  //            choreographerCompat.postFrameCallback(
  //                new ChoreographerCompat.FrameCallback() {
  //
  //                  private int frameCount = 0;
  //
  //                  @Override
  //                  public void doFrame(long frameTimeNanos) {
  //                    frameCount++;
  //                    if (frameCount == waitFrameCount) {
  //                      latch.countDown();
  //                    } else {
  //                      choreographerCompat.postFrameCallback(this);
  //                    }
  //                  }
  //                });
  //          }
  //        });
  //    try {
  //      if (!latch.await(timeToWait, TimeUnit.MILLISECONDS)) {
  //        throw new RuntimeException("Timed out waiting for Choreographer");
  //      }
  //    } catch (Exception e) {
  //      throw new RuntimeException(e);
  //    }
  //  }
  //
  //  private static void waitForJSIdle(ReactContext reactContext) {
  //    if (!reactContext.hasActiveCatalystInstance()) {
  //      return;
  //    }
  //    final CountDownLatch latch = new CountDownLatch(1);
  //
  //    reactContext.runOnJSQueueThread(
  //        new Runnable() {
  //          @Override
  //          public void run() {
  //            latch.countDown();
  //          }
  //        });
  //
  //    try {
  //      if (!latch.await(5000, TimeUnit.MILLISECONDS)) {
  //        throw new RuntimeException("Timed out waiting for JS thread");
  //      }
  //    } catch (Exception e) {
  //      throw new RuntimeException(e);
  //    }
  //  }
  //
  //  private static void waitInner(ReactBridgeIdleSignaler idleSignaler, long timeToWait) {
  //    // TODO gets broken in gradle, do we need it?
  //    Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
  //    long startTime = SystemClock.uptimeMillis();
  //    boolean bridgeWasIdle = false;
  //    while (SystemClock.uptimeMillis() - startTime < timeToWait) {
  //      boolean bridgeIsIdle = idleSignaler.isBridgeIdle();
  //      if (bridgeIsIdle && bridgeWasIdle) {
  //        return;
  //      }
  //      bridgeWasIdle = bridgeIsIdle;
  //      long newTimeToWait = Math.max(1, timeToWait - (SystemClock.uptimeMillis() - startTime));
  //      idleSignaler.waitForIdle(newTimeToWait);
  //      instrumentation.waitForIdleSync();
  //    }
  //    throw new RuntimeException("Timed out waiting for bridge and UI idle!");
  //  }
}
