// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

package org.chromium.chrome.browser.webapps;

import android.app.Instrumentation.ActivityMonitor;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.service.notification.StatusBarNotification;

import androidx.annotation.Nullable;
import androidx.test.filters.SmallTest;
import androidx.test.platform.app.InstrumentationRegistry;

import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.RuleChain;
import org.junit.rules.TestRule;
import org.junit.runner.RunWith;

import org.chromium.base.test.util.CommandLineFlags;
import org.chromium.base.test.util.CriteriaHelper;
import org.chromium.base.test.util.DisableIf;
import org.chromium.base.test.util.DisabledTest;
import org.chromium.base.test.util.Feature;
import org.chromium.chrome.browser.browserservices.intents.BrowserServicesIntentDataProvider;
import org.chromium.chrome.browser.browserservices.intents.WebappConstants;
import org.chromium.chrome.browser.customtabs.CustomTabNightModeStateController;
import org.chromium.chrome.browser.customtabs.DefaultBrowserProviderImpl;
import org.chromium.chrome.browser.customtabs.FakeDefaultBrowserProviderImpl;
import org.chromium.chrome.browser.customtabs.content.CustomTabIntentHandler;
import org.chromium.chrome.browser.customtabs.dependency_injection.BaseCustomTabActivityModule;
import org.chromium.chrome.browser.dependency_injection.ModuleOverridesRule;
import org.chromium.chrome.browser.flags.ChromeSwitches;
import org.chromium.chrome.browser.notifications.NotificationConstants;
import org.chromium.chrome.browser.theme.TopUiThemeColorProvider;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.chrome.test.R;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.net.test.EmbeddedTestServer;

/**
 * Tests for a standalone Web App notification governed by {@link WebappActionsNotificationManager}.
 */
@RunWith(ChromeJUnit4ClassRunner.class)
@CommandLineFlags.Add({ChromeSwitches.DISABLE_FIRST_RUN_EXPERIENCE})
public class WebappActionsNotificationTest {
    private static final String WEB_APP_PATH = "/chrome/test/data/banners/manifest_test_page.html";

    @Rule
    public final WebappActivityTestRule mActivityTestRule = new WebappActivityTestRule();

    private final TestRule mModuleOverridesRule =
            new ModuleOverridesRule().setOverride(BaseCustomTabActivityModule.Factory.class,
                    (BrowserServicesIntentDataProvider intentDataProvider,
                            CustomTabNightModeStateController nightModeController,
                            CustomTabIntentHandler.IntentIgnoringCriterion intentIgnoringCriterion,
                            TopUiThemeColorProvider topUiThemeColorProvider,
                            DefaultBrowserProviderImpl customTabDefaultBrowserProvider)
                            -> new BaseCustomTabActivityModule(intentDataProvider,
                                    nightModeController, intentIgnoringCriterion,
                                    topUiThemeColorProvider, new FakeDefaultBrowserProviderImpl()));

    @Rule
    public RuleChain mRuleChain =
            RuleChain.emptyRuleChain().around(mActivityTestRule).around(mModuleOverridesRule);

    private EmbeddedTestServer mTestServer;

    @Before
    public void startWebapp() {
        Context appContext = InstrumentationRegistry.getInstrumentation()
                                     .getTargetContext()
                                     .getApplicationContext();
        mTestServer = EmbeddedTestServer.createAndStartServer(appContext);
        mActivityTestRule.startWebappActivity(mActivityTestRule.createIntent().putExtra(
                WebappConstants.EXTRA_URL, mTestServer.getURL(WEB_APP_PATH)));
    }

    @Test
    @SmallTest
    @Feature({"Webapps"})
    @DisableIf.Build(sdk_is_less_than = Build.VERSION_CODES.O, message = "crbug/1267965")
    public void testNotification_openInChrome() throws Exception {
        Notification notification = getWebappNotification();

        Assert.assertNotNull(notification);
        Assert.assertEquals(
                "webapp short name", notification.extras.getString(Notification.EXTRA_TITLE));
        Assert.assertEquals(
                mActivityTestRule.getActivity().getString(R.string.webapp_tap_to_copy_url),
                notification.extras.getString(Notification.EXTRA_TEXT));
        Assert.assertEquals("Share", notification.actions[0].title);
        Assert.assertEquals("Open in Chrome", notification.actions[1].title);

        IntentFilter filter = new IntentFilter(Intent.ACTION_VIEW);
        filter.addDataScheme("http");
        final ActivityMonitor monitor =
                InstrumentationRegistry.getInstrumentation().addMonitor(filter, null, false);

        notification.actions[1].actionIntent.send();
        CriteriaHelper.pollInstrumentationThread(() -> {
            return InstrumentationRegistry.getInstrumentation().checkMonitorHit(monitor, 1);
        });

        Assert.assertNull("Notification should no longer be shown", getWebappNotification());
    }

    @Test
    @SmallTest
    @Feature({"Webapps"})
    @DisabledTest(message = "crbug.com/774491")
    public void testNotification_copyUrl() throws Exception {
        Notification notification = getWebappNotification();
        Assert.assertNotNull(notification);

        notification.contentIntent.send();

        TestThreadUtils.runOnUiThreadBlocking(() -> {
            ClipboardManager clipboard =
                    (ClipboardManager) mActivityTestRule.getActivity().getSystemService(
                            Context.CLIPBOARD_SERVICE);
            Assert.assertEquals(mActivityTestRule.getTestServer().getURL(WEB_APP_PATH),
                    clipboard.getPrimaryClip().getItemAt(0).getText().toString());
        });
    }

    private @Nullable Notification getWebappNotification() {
        NotificationManager nm =
                (NotificationManager) mActivityTestRule.getActivity().getSystemService(
                        Context.NOTIFICATION_SERVICE);
        for (StatusBarNotification sbn : nm.getActiveNotifications()) {
            if (sbn.getId() == NotificationConstants.NOTIFICATION_ID_WEBAPP_ACTIONS) {
                return sbn.getNotification();
            }
        }
        return null;
    }
}
