// Copyright 2019 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package android.support.customtabs.trusted.splashscreens;

import static android.support.customtabs.TrustedWebUtils.EXTRA_SPLASH_SCREEN_PARAMS;
import static android.support.customtabs.testutil.TestUtil.runOnUiThreadBlocking;

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;

import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.net.Uri;
import android.os.Bundle;
import android.support.customtabs.CustomTabsSession;
import android.support.customtabs.EnableComponentsTestRule;
import android.support.customtabs.TestActivity;
import android.support.customtabs.TestCustomTabsService;
import android.support.customtabs.TestCustomTabsServiceNoSplashScreens;
import android.support.customtabs.TestCustomTabsServiceSupportsTwas;
import android.support.customtabs.TrustedWebUtils.SplashScreenParamKey;
import android.support.customtabs.test.R;
import android.support.customtabs.testutil.CustomTabConnectionRule;
import android.support.customtabs.testutil.TestUtil;
import android.support.customtabs.trusted.TestBrowser;
import android.support.customtabs.trusted.TrustedWebActivityIntentBuilder;
import android.support.test.InstrumentationRegistry;
import android.support.test.filters.MediumTest;
import android.support.test.rule.ActivityTestRule;
import android.support.test.runner.AndroidJUnit4;
import android.view.View;
import android.widget.ImageView;

import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.io.File;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

/**
 * Tests for {@link PwaWrapperSplashScreenStrategy}.
 */
@RunWith(AndroidJUnit4.class)
@MediumTest
public class PwaWrapperSplashScreenStrategyTest {

    // For clean-up. See SplashImageTransferTask.java.
    private static final String FOLDER_NAME = "twa_splash";
    private static final String FILE_PROVIDER_AUTHORITY =
            "android.support.customtabs.trusted.test_fileprovider";

    @Rule
    public final EnableComponentsTestRule mEnableComponents = new EnableComponentsTestRule(
            TestActivity.class,
            TestBrowser.class,
            TestCustomTabsServiceSupportsTwas.class
    );

    @Rule
    public final ActivityTestRule<TestActivity> mActivityTestRule =
            new ActivityTestRule<>(TestActivity.class, false, true);

    @Rule
    public final CustomTabConnectionRule mConnectionRule = new CustomTabConnectionRule();

    private TestActivity mActivity;
    private CustomTabsSession mSession;
    private PwaWrapperSplashScreenStrategy mStrategy;

    @Before
    public void setUp() {
        mActivity = mActivityTestRule.getActivity();
        mSession = mConnectionRule.establishSessionBlocking(mActivity);
        mStrategy = new PwaWrapperSplashScreenStrategy(mActivity, R.drawable.splash, 0,
                ImageView.ScaleType.FIT_XY, null, 0, FILE_PROVIDER_AUTHORITY);
    }

    @After
    public void tearDown() {
        new File(mActivity.getFilesDir(), FOLDER_NAME).delete(); // Clean up save splash image file.
    }

    @Test
    public void showsSplashScreenInClient_WhenTwaLaunchInitiated() {
        initiateLaunch(mStrategy);
        InstrumentationRegistry.getInstrumentation().waitForIdleSync();

        // The splash screen should be full-screen blue. Check just one pixel.
        assertEquals(mActivity.getColor(R.color.splash_screen_color), getColorOfAPixel());
    }

    @Test
    public void doesntShowsSplashScreenInClient_IfSplashScreensNotSupported() {
        mEnableComponents.manuallyDisable(TestCustomTabsServiceSupportsTwas.class);
        mEnableComponents.manuallyEnable(TestCustomTabsServiceNoSplashScreens.class);

        initiateLaunch(mStrategy);
        InstrumentationRegistry.getInstrumentation().waitForIdleSync();
        assertNotEquals(mActivity.getColor(R.color.splash_screen_color), getColorOfAPixel());
    }

    @Test
    public void imageFileIsSuccessfullyTransferredToService() {
        initiateLaunch(mStrategy);
        mStrategy.configureTwaBuilder(new TrustedWebActivityIntentBuilder(Uri.EMPTY),
                mSession, null);
        assertTrue(TestCustomTabsService.getInstance().waitForSplashImageFile(3000));
    }

    @Test
    public void setsParametersOnTwaBuilder() throws InterruptedException {
        int bgColor = 0x115599;
        ImageView.ScaleType scaleType = ImageView.ScaleType.MATRIX;
        Matrix matrix = new Matrix();
        matrix.setSkew(1, 2, 3, 4);
        int fadeOutDuration = 300;

        PwaWrapperSplashScreenStrategy strategy = new PwaWrapperSplashScreenStrategy(mActivity,
                R.drawable.splash, bgColor, scaleType, matrix, fadeOutDuration,
                FILE_PROVIDER_AUTHORITY);
        strategy.onActivityEnterAnimationComplete();
        initiateLaunch(strategy);

        TrustedWebActivityIntentBuilder builder = new TrustedWebActivityIntentBuilder(
                Uri.parse("https://test.com"));

        CountDownLatch latch = new CountDownLatch(1);
        strategy.configureTwaBuilder(builder, mSession, latch::countDown);
        assertTrue(latch.await(3, TimeUnit.SECONDS));

        Intent intent = TestUtil.getBrowserActivityWhenLaunched(
                () -> mActivity.startActivity(builder.build(mSession))).getIntent();
        Bundle bundle = intent.getBundleExtra(EXTRA_SPLASH_SCREEN_PARAMS);

        assertEquals(bgColor, bundle.getInt(SplashScreenParamKey.BACKGROUND_COLOR));
        assertEquals(scaleType.ordinal(), bundle.getInt(SplashScreenParamKey.SCALE_TYPE));
        assertEquals(fadeOutDuration, bundle.getInt(SplashScreenParamKey.FADE_OUT_DURATION_MS));

        float[] matrixValues = new float[9];
        matrix.getValues(matrixValues);
        assertArrayEquals(matrixValues, bundle.getFloatArray(
                SplashScreenParamKey.IMAGE_TRANSFORMATION_MATRIX), 1e-3f);
    }

    @Test
    public void waitsForEnterAnimationCompletion_BeforeDeclaringReady()
            throws InterruptedException {
        initiateLaunch(mStrategy);
        Runnable readyCallback = mock(Runnable.class);
        mStrategy.configureTwaBuilder(new TrustedWebActivityIntentBuilder( Uri.EMPTY),
                mSession, readyCallback);
        TestCustomTabsService.getInstance().waitForSplashImageFile(3000);

        CountDownLatch latch = new CountDownLatch(1);
        runOnUiThreadBlocking(() -> {
            verify(readyCallback, never()).run();
            mStrategy.onActivityEnterAnimationComplete();
            verify(readyCallback).run();
            latch.countDown();
        });
        assertTrue(latch.await(3, TimeUnit.SECONDS));
    }

    private void initiateLaunch(PwaWrapperSplashScreenStrategy strategy) {
        runOnUiThreadBlocking(() ->  strategy.onTwaLaunchInitiated(mActivity.getPackageName(),
                new TrustedWebActivityIntentBuilder(Uri.EMPTY)));
    }

    private int getColorOfAPixel() {
        View view = runOnUiThreadBlocking(() -> mActivity.findViewById(android.R.id.content));
        Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
        Canvas canvas = new Canvas(bitmap);
        view.draw(canvas);
        return bitmap.getPixel(0, 0);
    }

}