// 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 io.flutter.plugins.quickactionsexample;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

import android.content.Context;
import android.content.Intent;
import android.content.pm.ShortcutInfo;
import android.content.pm.ShortcutManager;
import android.util.Log;
import androidx.lifecycle.Lifecycle;
import androidx.test.core.app.ActivityScenario;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.Until;
import io.flutter.plugins.quickactions.QuickActionsPlugin;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

@RunWith(AndroidJUnit4.class)
public class QuickActionsTest {
  private Context context;
  private UiDevice device;
  private ActivityScenario<QuickActionsTestActivity> scenario;

  @Before
  public void setUp() {
    context = ApplicationProvider.getApplicationContext();
    device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
    scenario = ensureAppRunToView();
    ensureAllAppShortcutsAreCreated();
  }

  @After
  public void tearDown() {
    scenario.close();
    Log.i(QuickActionsTest.class.getSimpleName(), "Run to completion");
  }

  @Test
  public void quickActionPluginIsAdded() {
    final ActivityScenario<QuickActionsTestActivity> scenario =
        ActivityScenario.launch(QuickActionsTestActivity.class);
    scenario.onActivity(
        activity -> {
          assertTrue(activity.engine.getPlugins().has(QuickActionsPlugin.class));
        });
  }

  @Test
  public void appShortcutsAreCreated() {
    List<ShortcutInfo> expectedShortcuts = createMockShortcuts();

    ShortcutManager shortcutManager =
        (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);
    List<ShortcutInfo> dynamicShortcuts = shortcutManager.getDynamicShortcuts();

    // Assert the app shortcuts defined in ../lib/main.dart.
    assertFalse(dynamicShortcuts.isEmpty());
    assertEquals(expectedShortcuts.size(), dynamicShortcuts.size());
    for (ShortcutInfo expectedShortcut : expectedShortcuts) {
      ShortcutInfo dynamicShortcut =
          dynamicShortcuts
              .stream()
              .filter(s -> s.getId().equals(expectedShortcut.getId()))
              .findFirst()
              .get();

      assertEquals(expectedShortcut.getShortLabel(), dynamicShortcut.getShortLabel());
      assertEquals(expectedShortcut.getLongLabel(), dynamicShortcut.getLongLabel());
    }
  }

  @Test
  public void appShortcutLaunchActivityAfterStarting() {
    // Arrange
    List<ShortcutInfo> shortcuts = createMockShortcuts();
    ShortcutInfo firstShortcut = shortcuts.get(0);
    ShortcutManager shortcutManager =
        (ShortcutManager) context.getSystemService(Context.SHORTCUT_SERVICE);
    List<ShortcutInfo> dynamicShortcuts = shortcutManager.getDynamicShortcuts();
    ShortcutInfo dynamicShortcut =
        dynamicShortcuts
            .stream()
            .filter(s -> s.getId().equals(firstShortcut.getId()))
            .findFirst()
            .get();
    Intent dynamicShortcutIntent = dynamicShortcut.getIntent();
    AtomicReference<QuickActionsTestActivity> initialActivity = new AtomicReference<>();
    scenario.onActivity(initialActivity::set);
    String appReadySentinel = " has launched";

    // Act
    context.startActivity(dynamicShortcutIntent);
    device.wait(Until.hasObject(By.descContains(appReadySentinel)), 2000);
    AtomicReference<QuickActionsTestActivity> currentActivity = new AtomicReference<>();
    scenario.onActivity(currentActivity::set);

    // Assert
    Assert.assertTrue(
        "AppShortcut:" + firstShortcut.getId() + " does not launch the correct activity",
        // We can only find the shortcut type in content description while inspecting it in Ui
        // Automator Viewer.
        device.hasObject(By.descContains(firstShortcut.getId() + appReadySentinel)));
    // This is Android SingleTop behavior in which Android does not destroy the initial activity and
    // launch a new activity.
    Assert.assertEquals(initialActivity.get(), currentActivity.get());
  }

  private void ensureAllAppShortcutsAreCreated() {
    device.wait(Until.hasObject(By.text("actions ready")), 1000);
  }

  private List<ShortcutInfo> createMockShortcuts() {
    List<ShortcutInfo> expectedShortcuts = new ArrayList<>();

    String actionOneLocalizedTitle = "Action one";
    expectedShortcuts.add(
        new ShortcutInfo.Builder(context, "action_one")
            .setShortLabel(actionOneLocalizedTitle)
            .setLongLabel(actionOneLocalizedTitle)
            .build());

    String actionTwoLocalizedTitle = "Action two";
    expectedShortcuts.add(
        new ShortcutInfo.Builder(context, "action_two")
            .setShortLabel(actionTwoLocalizedTitle)
            .setLongLabel(actionTwoLocalizedTitle)
            .build());

    return expectedShortcuts;
  }

  private ActivityScenario<QuickActionsTestActivity> ensureAppRunToView() {
    final ActivityScenario<QuickActionsTestActivity> scenario =
        ActivityScenario.launch(QuickActionsTestActivity.class);
    scenario.moveToState(Lifecycle.State.STARTED);
    return scenario;
  }
}
