// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package dev.flutter.scenarios;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Choreographer;
import androidx.annotation.NonNull;
import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.plugin.common.BasicMessageChannel;
import io.flutter.plugin.common.BinaryCodec;
import io.flutter.plugin.common.JSONMethodCodec;
import io.flutter.plugin.common.MethodChannel;
import java.io.FileDescriptor;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicBoolean;

public class TextPlatformViewActivity extends TestableFlutterActivity {
  static final String TAG = "Scenarios";

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    final Intent launchIntent = getIntent();
    if ("com.google.intent.action.TEST_LOOP".equals(launchIntent.getAction())) {
      if (Build.VERSION.SDK_INT > 22) {
        requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
      }
      // Run for one minute, get the timeline data, write it, and finish.
      final Uri logFileUri = launchIntent.getData();
      new Handler()
          .postDelayed(
              new Runnable() {
                @Override
                public void run() {
                  writeTimelineData(logFileUri);

                  testFlutterLoaderCallbackWhenInitializedTwice();
                }
              },
              20000);
    } else {
      testFlutterLoaderCallbackWhenInitializedTwice();
    }
  }

  @Override
  @NonNull
  public FlutterShellArgs getFlutterShellArgs() {
    FlutterShellArgs args = FlutterShellArgs.fromIntent(getIntent());
    args.add(FlutterShellArgs.ARG_TRACE_STARTUP);
    args.add(FlutterShellArgs.ARG_ENABLE_DART_PROFILING);
    args.add(FlutterShellArgs.ARG_VERBOSE_LOGGING);
    return args;
  }

  @Override
  public void configureFlutterEngine(FlutterEngine flutterEngine) {
    flutterEngine
        .getPlatformViewsController()
        .getRegistry()
        .registerViewFactory("scenarios/textPlatformView", new TextPlatformViewFactory());
  }

  @Override
  public void onFlutterUiDisplayed() {
    final Intent launchIntent = getIntent();
    if (!launchIntent.hasExtra("scenario")) {
      return;
    }
    MethodChannel channel =
        new MethodChannel(getFlutterEngine().getDartExecutor(), "driver", JSONMethodCodec.INSTANCE);
    Map<String, Object> test = new HashMap<>(2);
    test.put("name", launchIntent.getStringExtra("scenario"));
    test.put("use_android_view", launchIntent.getBooleanExtra("use_android_view", false));
    channel.invokeMethod("set_scenario", test);

    notifyFlutterRenderedAfterVsync();
  }

  private void notifyFlutterRenderedAfterVsync() {
    // Wait 1s after the next frame, so the Android texture are rendered.
    Choreographer.getInstance()
        .postFrameCallbackDelayed(
            new Choreographer.FrameCallback() {
              @Override
              public void doFrame(long frameTimeNanos) {
                reportFullyDrawn();
                notifyFlutterRendered();
              }
            },
            1000L);
  }

  private void writeTimelineData(Uri logFile) {
    if (logFile == null) {
      throw new IllegalArgumentException();
    }
    if (getFlutterEngine() == null) {
      Log.e(TAG, "Could not write timeline data - no engine.");
      return;
    }
    final BasicMessageChannel<ByteBuffer> channel =
        new BasicMessageChannel<>(
            getFlutterEngine().getDartExecutor(), "write_timeline", BinaryCodec.INSTANCE);
    channel.send(
        null,
        (ByteBuffer reply) -> {
          try {
            final FileDescriptor fd =
                getContentResolver().openAssetFileDescriptor(logFile, "w").getFileDescriptor();
            final FileOutputStream outputStream = new FileOutputStream(fd);
            outputStream.write(reply.array());
            outputStream.close();
          } catch (IOException ex) {
            Log.e(TAG, "Could not write timeline file: " + ex.toString());
          }
          finish();
        });
  }

  /**
   * This method verifies that {@link FlutterLoader#ensureInitializationCompleteAsync(Context,
   * String[], Handler, Runnable)} invokes its callback when called after initialization.
   */
  private void testFlutterLoaderCallbackWhenInitializedTwice() {
    FlutterLoader flutterLoader = new FlutterLoader();

    // Flutter is probably already loaded in this app based on
    // code that ran before this method. Nonetheless, invoke the
    // blocking initialization here to ensure it's initialized.
    flutterLoader.startInitialization(getApplicationContext());
    flutterLoader.ensureInitializationComplete(getApplication(), new String[] {});

    // Now that Flutter is loaded, invoke ensureInitializationCompleteAsync with
    // a callback and verify that the callback is invoked.
    Handler mainHandler = new Handler(Looper.getMainLooper());

    final AtomicBoolean didInvokeCallback = new AtomicBoolean(false);

    flutterLoader.ensureInitializationCompleteAsync(
        getApplication(),
        new String[] {},
        mainHandler,
        new Runnable() {
          @Override
          public void run() {
            didInvokeCallback.set(true);
          }
        });

    mainHandler.post(
        new Runnable() {
          @Override
          public void run() {
            if (!didInvokeCallback.get()) {
              throw new RuntimeException(
                  "Failed test: FlutterLoader#ensureInitializationCompleteAsync() did not invoke its callback.");
            }
          }
        });
  }
}
