/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.samples.browser

import android.os.SystemClock
import androidx.test.espresso.Espresso.onView
import androidx.test.espresso.action.ViewActions.click
import androidx.test.espresso.action.ViewActions.pressImeActionButton
import androidx.test.espresso.action.ViewActions.replaceText
import androidx.test.espresso.assertion.ViewAssertions.matches
import androidx.test.espresso.matcher.ViewMatchers.withContentDescription
import androidx.test.espresso.matcher.ViewMatchers.withId
import androidx.test.espresso.matcher.ViewMatchers.withText
import androidx.test.ext.junit.rules.ActivityScenarioRule
import androidx.test.filters.LargeTest
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import androidx.test.uiautomator.UiSelector
import mozilla.components.support.android.test.rules.WebserverRule
import org.junit.Assert.assertTrue
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import java.util.concurrent.TimeUnit
import mozilla.components.browser.toolbar.R as toolbarR
import mozilla.components.feature.tabs.R as tabsR

private const val INITIAL_WAIT_SECONDS = 5L
private const val WAIT_FOR_WEB_CONTENT_SECONDS = 15L

/**
 * A collection of "smoke tests" to verify that the basic browsing functionality is working.
 */

@LargeTest
class SmokeTests {
    @get:Rule
    val activityRule: ActivityScenarioRule<BrowserActivity> = ActivityScenarioRule(BrowserActivity::class.java)

    @get:Rule
    val webserverRule: WebserverRule = WebserverRule()

    /**
     * This test loads a website from a local webserver by typing into the URL bar. After that it verifies that the
     * web content is visible.
     */

    @Test
    fun loadWebsiteTest() {
        waitForIdle()

        enterUrl(webserverRule.url())

        verifyWebsiteContent("Hello World!")
        verifyUrlInToolbar(webserverRule.url())
    }

    @Ignore("Intermittent: https://bugzilla.mozilla.org/show_bug.cgi?id=1794873")
    @Test
    fun loadWebsitesInMultipleTabsTest() {
        waitForIdle()

        enterUrl(webserverRule.url())

        verifyWebsiteContent("Hello World!")
        verifyUrlInToolbar(webserverRule.url())

        navigateToTabsTray()
        openNewTabInTabsTray()

        enterUrl(webserverRule.url())

        verifyWebsiteContent("Hello World!")
        verifyUrlInToolbar(webserverRule.url())

        navigateToTabsTray()
        openNewTabInTabsTray()

        enterUrl(webserverRule.url())

        verifyWebsiteContent("Hello World!")
        verifyUrlInToolbar(webserverRule.url())

        navigateToTabsTray()
        openNewTabInTabsTray()
    }
}

private fun waitForIdle() {
    // Meh! We need a better idle strategy here. Because of bug 1441059 our load request gets lost if it happens
    // to fast and then only "about:blank" gets loaded. So a "quick" fix here is to just wait a bit.
    // https://bugzilla.mozilla.org/show_bug.cgi?id=1441059
    SystemClock.sleep(TimeUnit.SECONDS.toMillis(INITIAL_WAIT_SECONDS))
}

private fun navigateToTabsTray() {
    onView(withContentDescription(tabsR.string.mozac_feature_tabs_toolbar_tabs_button))
        .perform(click())
}

private fun openNewTabInTabsTray() {
    onView(withId(R.id.newTab))
        .perform(click())
}

private fun enterUrl(url: String) {
    onView(withId(toolbarR.id.mozac_browser_toolbar_url_view))
        .perform(click())

    onView(withId(toolbarR.id.mozac_browser_toolbar_edit_url_view))
        .perform(replaceText(url), pressImeActionButton())
}

private fun verifyUrlInToolbar(url: String) {
    onView(withId(toolbarR.id.mozac_browser_toolbar_url_view))
        .check(matches(withText(url)))
}

private fun verifyWebsiteContent(text: String) {
    val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
    device.waitForIdle()

    val waitingTime: Long = TimeUnit.SECONDS.toMillis(WAIT_FOR_WEB_CONTENT_SECONDS)

    assertTrue(
        device
            .findObject(
                UiSelector()
                    .textContains(text),
            )
            .waitForExists(waitingTime),
    )
}
