// Copyright 2019 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.contextmenu;

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;

import android.graphics.Bitmap;
import android.graphics.drawable.BitmapDrawable;
import android.text.TextUtils;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;

import androidx.test.filters.SmallTest;

import org.junit.Test;
import org.junit.runner.RunWith;

import org.chromium.base.test.util.Batch;
import org.chromium.chrome.R;
import org.chromium.chrome.test.ChromeJUnit4ClassRunner;
import org.chromium.content_public.browser.test.util.TestThreadUtils;
import org.chromium.ui.modelutil.PropertyModel;
import org.chromium.ui.modelutil.PropertyModelChangeProcessor;
import org.chromium.ui.test.util.BlankUiTestActivityTestCase;

/**
 * Tests for ContextMenuHeader view and {@link ContextMenuHeaderViewBinder}
 */
@RunWith(ChromeJUnit4ClassRunner.class)
@Batch(Batch.UNIT_TESTS)
public class ContextMenuHeaderViewTest extends BlankUiTestActivityTestCase {
    private static final String TITLE_STRING = "Some Very Cool Title";
    private static final String URL_STRING = "www.website.com";

    private View mHeaderView;
    private TextView mTitle;
    private TextView mUrl;
    private View mTitleAndUrl;
    private ImageView mImage;
    private View mCircleBg;
    private View mImageContainer;
    private PropertyModel mModel;
    private PropertyModelChangeProcessor mMCP;

    @Override
    public void setUpTest() throws Exception {
        super.setUpTest();

        TestThreadUtils.runOnUiThreadBlocking(() -> {
            getActivity().setContentView(R.layout.context_menu_header);
            mHeaderView = getActivity().findViewById(android.R.id.content);
            mTitle = mHeaderView.findViewById(R.id.menu_header_title);
            mUrl = mHeaderView.findViewById(R.id.menu_header_url);
            mTitleAndUrl = mHeaderView.findViewById(R.id.title_and_url);
            mImage = mHeaderView.findViewById(R.id.menu_header_image);
            mCircleBg = mHeaderView.findViewById(R.id.circle_background);
            mImageContainer = mHeaderView.findViewById(R.id.menu_header_image_container);
            mModel = new PropertyModel.Builder(ContextMenuHeaderProperties.ALL_KEYS)
                             .with(ContextMenuHeaderProperties.TITLE, "")
                             .with(ContextMenuHeaderProperties.URL, "")
                             .with(ContextMenuHeaderProperties.TITLE_AND_URL_CLICK_LISTENER, null)
                             .with(ContextMenuHeaderProperties.IMAGE, null)
                             .with(ContextMenuHeaderProperties.CIRCLE_BG_VISIBLE, false)
                             .build();

            mMCP = PropertyModelChangeProcessor.create(
                    mModel, mHeaderView, ContextMenuHeaderViewBinder::bind);
        });
    }

    @Override
    public void tearDownTest() throws Exception {
        TestThreadUtils.runOnUiThreadBlocking(mMCP::destroy);
        super.tearDownTest();
    }

    @Test
    @SmallTest
    public void testTitle() {
        assertThat(
                "Incorrect initial title visibility.", mTitle.getVisibility(), equalTo(View.GONE));

        TestThreadUtils.runOnUiThreadBlocking(() -> {
            mModel.set(ContextMenuHeaderProperties.TITLE, TITLE_STRING);
            mModel.set(ContextMenuHeaderProperties.TITLE_MAX_LINES, 2);
        });

        assertThat("Incorrect title visibility.", mTitle.getVisibility(), equalTo(View.VISIBLE));
        assertThat("Incorrect title string.", mTitle.getText(), equalTo(TITLE_STRING));
        assertThat("Incorrect max line count for title.", mTitle.getMaxLines(), equalTo(2));
        assertThat("Incorrect title ellipsize mode.", mTitle.getEllipsize(),
                equalTo(TextUtils.TruncateAt.END));
    }

    @Test
    @SmallTest
    public void testUrl() {
        assertThat("Incorrect initial URL visibility.", mUrl.getVisibility(), equalTo(View.GONE));

        TestThreadUtils.runOnUiThreadBlocking(() -> {
            mModel.set(ContextMenuHeaderProperties.URL, URL_STRING);
            mModel.set(ContextMenuHeaderProperties.URL_MAX_LINES, 1);
        });

        assertThat("Incorrect URL visibility.", mUrl.getVisibility(), equalTo(View.VISIBLE));
        assertThat("Incorrect URL string.", mUrl.getText(), equalTo(URL_STRING));
        assertThat("Incorrect max line count for URL.", mUrl.getMaxLines(), equalTo(1));
        assertThat("Incorrect URL ellipsize mode.", mUrl.getEllipsize(),
                equalTo(TextUtils.TruncateAt.END));

        TestThreadUtils.runOnUiThreadBlocking(
                () -> mModel.set(ContextMenuHeaderProperties.URL_MAX_LINES, Integer.MAX_VALUE));

        assertThat("Incorrect max line count for URL.", mUrl.getMaxLines(),
                equalTo(Integer.MAX_VALUE));
        assertNull("URL is ellipsized when it shouldn't be.", mUrl.getEllipsize());
    }

    @Test
    @SmallTest
    public void testTitleAndUrlClick() {
        // Clicking on the title or the URL expands/shrinks both of them.
        assertFalse("Title and URL have onClickListeners when it shouldn't, yet, have.",
                mTitleAndUrl.hasOnClickListeners());

        TestThreadUtils.runOnUiThreadBlocking(() -> {
            mModel.set(ContextMenuHeaderProperties.TITLE, TITLE_STRING);
            mModel.set(ContextMenuHeaderProperties.TITLE_MAX_LINES, 1);
            mModel.set(ContextMenuHeaderProperties.URL, URL_STRING);
            mModel.set(ContextMenuHeaderProperties.URL_MAX_LINES, 1);
            mModel.set(ContextMenuHeaderProperties.TITLE_AND_URL_CLICK_LISTENER, (v) -> {
                if (mModel.get(ContextMenuHeaderProperties.URL_MAX_LINES) == Integer.MAX_VALUE) {
                    mModel.set(ContextMenuHeaderProperties.TITLE_MAX_LINES, 1);
                    mModel.set(ContextMenuHeaderProperties.URL_MAX_LINES, 1);
                } else {
                    mModel.set(ContextMenuHeaderProperties.TITLE_MAX_LINES, Integer.MAX_VALUE);
                    mModel.set(ContextMenuHeaderProperties.URL_MAX_LINES, Integer.MAX_VALUE);
                }
            });
            mTitleAndUrl.callOnClick();
        });

        assertThat("Incorrect max line count for title.", mTitle.getMaxLines(),
                equalTo(Integer.MAX_VALUE));
        assertNull("Title is ellipsized when it shouldn't be.", mTitle.getEllipsize());
        assertThat("Incorrect max line count for URL.", mUrl.getMaxLines(),
                equalTo(Integer.MAX_VALUE));
        assertNull("URL is ellipsized when it shouldn't be.", mUrl.getEllipsize());

        TestThreadUtils.runOnUiThreadBlocking(() -> { mTitleAndUrl.callOnClick(); });

        assertThat("Incorrect max line count for title.", mTitle.getMaxLines(), equalTo(1));
        assertThat("Incorrect title ellipsize mode.", mTitle.getEllipsize(),
                equalTo(TextUtils.TruncateAt.END));
        assertThat("Incorrect max line count for URL.", mUrl.getMaxLines(), equalTo(1));
        assertThat("Incorrect URL ellipsize mode.", mUrl.getEllipsize(),
                equalTo(TextUtils.TruncateAt.END));
    }

    @Test
    @SmallTest
    public void testImage() {
        assertThat("Incorrect initial circle background visibility.", mCircleBg.getVisibility(),
                equalTo(View.INVISIBLE));
        TestThreadUtils.runOnUiThreadBlocking(
                () -> mModel.set(ContextMenuHeaderProperties.CIRCLE_BG_VISIBLE, true));
        assertThat("Incorrect circle background visibility.", mCircleBg.getVisibility(),
                equalTo(View.VISIBLE));

        assertFalse("Thumbnail drawable should use fallback color initially.",
                mImage.getDrawable() instanceof BitmapDrawable);
        final Bitmap bitmap = Bitmap.createBitmap(4, 4, Bitmap.Config.ARGB_8888);
        TestThreadUtils.runOnUiThreadBlocking(
                () -> mModel.set(ContextMenuHeaderProperties.IMAGE, bitmap));
        assertThat("Incorrect thumbnail bitmap.",
                ((BitmapDrawable) mImage.getDrawable()).getBitmap(), equalTo(bitmap));
    }
}
