/* 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.fenix.ui

import androidx.compose.ui.test.junit4.AndroidComposeTestRule
import androidx.test.espresso.Espresso.pressBack
import okhttp3.mockwebserver.MockWebServer
import org.junit.After
import org.junit.Before
import org.junit.Ignore
import org.junit.Rule
import org.junit.Test
import org.mozilla.fenix.customannotations.SmokeTest
import org.mozilla.fenix.helpers.AndroidAssetDispatcher
import org.mozilla.fenix.helpers.HomeActivityIntentTestRule
import org.mozilla.fenix.helpers.MockBrowserDataHelper.addCustomSearchEngine
import org.mozilla.fenix.helpers.MockBrowserDataHelper.createBookmarkItem
import org.mozilla.fenix.helpers.MockBrowserDataHelper.createHistoryItem
import org.mozilla.fenix.helpers.SearchDispatcher
import org.mozilla.fenix.helpers.TestAssetHelper.getGenericAsset
import org.mozilla.fenix.helpers.TestHelper.appContext
import org.mozilla.fenix.helpers.TestHelper.exitMenu
import org.mozilla.fenix.helpers.TestHelper.restartApp
import org.mozilla.fenix.helpers.TestHelper.runWithSystemLocaleChanged
import org.mozilla.fenix.helpers.TestHelper.setSystemLocale
import org.mozilla.fenix.helpers.TestHelper.setTextToClipBoard
import org.mozilla.fenix.helpers.TestHelper.verifySnackBarText
import org.mozilla.fenix.ui.robots.EngineShortcut
import org.mozilla.fenix.ui.robots.homeScreen
import org.mozilla.fenix.ui.robots.searchScreen
import java.util.Locale

class SettingsSearchTest {
    private lateinit var mockWebServer: MockWebServer
    private lateinit var searchMockServer: MockWebServer
    private val defaultSearchEngineList =
        listOf(
            "Bing",
            "DuckDuckGo",
            "Google",
        )

    @get:Rule
    val activityTestRule = AndroidComposeTestRule(
        HomeActivityIntentTestRule.withDefaultSettingsOverrides(),
    ) { it.activity }

    @Before
    fun setUp() {
        mockWebServer = MockWebServer().apply {
            dispatcher = AndroidAssetDispatcher()
            start()
        }

        searchMockServer = MockWebServer().apply {
            dispatcher = SearchDispatcher()
            start()
        }
    }

    @After
    fun tearDown() {
        mockWebServer.shutdown()
    }

    @Test
    fun searchSettingsItemsTest() {
        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            verifyToolbarText("Search")
            verifySearchEnginesSectionHeader()
            verifyDefaultSearchEngineHeader()
            verifyDefaultSearchEngineSummary("Google")
            verifyManageSearchShortcutsHeader()
            verifyManageShortcutsSummary()
            verifyAddressBarSectionHeader()
            verifyAutocompleteURlsIsEnabled(true)
            verifyShowClipboardSuggestionsEnabled(true)
            verifySearchBrowsingHistoryEnabled(true)
            verifySearchBookmarksEnabled(true)
            verifySearchSyncedTabsEnabled(true)
            verifyVoiceSearchEnabled(true)
            verifyShowSearchSuggestionsEnabled(true)
            verifyShowSearchSuggestionsInPrivateEnabled(false)
        }
    }

    @Test
    fun defaultSearchEnginesSettingsItemsTest() {
        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            verifyDefaultSearchEngineHeader()
            openDefaultSearchEngineMenu()
            verifyToolbarText("Default search engine")
            verifyDefaultSearchEngineList()
            verifyDefaultSearchEngineSelected("Google")
        }
    }

    @SmokeTest
    @Test
    fun selectNewDefaultSearchEngine() {
        // Goes through the settings and changes the default search engine, then verifies it has changed.
        defaultSearchEngineList.forEach {
            homeScreen {
            }.openThreeDotMenu {
            }.openSettings {
            }.openSearchSubMenu {
                openDefaultSearchEngineMenu()
                changeDefaultSearchEngine(it)
                exitMenu()
            }
            searchScreen {
                verifySearchEngineIcon(it)
            }
        }
    }

    @Test
    fun toggleSearchAutocomplete() {
        homeScreen {
        }.openSearch {
            typeSearch("mo")
            verifyTypedToolbarText("monster.com")
            typeSearch("moz")
            verifyTypedToolbarText("mozilla.org")
        }.dismissSearchBar {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            toggleAutocomplete()
        }.goBack {
        }.goBack {
        }.openSearch {
            typeSearch("moz")
            verifyTypedToolbarText("moz")
        }
    }

    @Test
    fun toggleOffHistorySearchSuggestionsTest() {
        val websiteURL = getGenericAsset(mockWebServer, 1).url.toString()

        createHistoryItem(websiteURL)

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            switchSearchHistoryToggle()
            exitMenu()
        }

        homeScreen {
        }.openSearch {
            typeSearch("test")
            verifyNoSuggestionsAreDisplayed(
                activityTestRule,
                "Firefox Suggest",
                websiteURL,
            )
        }
    }

    @Test
    fun toggleOffBookmarksSearchSuggestionsTest() {
        val website = getGenericAsset(mockWebServer, 1)

        createBookmarkItem(website.url.toString(), website.title, 1u)

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            switchSearchBookmarksToggle()
            // We want to avoid confusion between history and bookmarks searches,
            // so we'll disable this too.
            switchSearchHistoryToggle()
            exitMenu()
        }

        homeScreen {
        }.openSearch {
            typeSearch("test")
            verifyNoSuggestionsAreDisplayed(
                activityTestRule,
                "Firefox Suggest",
                website.title,
            )
        }
    }

    // Verifies setting as default a customized search engine name and URL
    @SmokeTest
    @Test
    fun addCustomDefaultSearchEngineTest() {
        val customSearchEngine = object {
            val title = "TestSearchEngine"
            val url = "http://localhost:${searchMockServer.port}/searchResults.html?search=%s"
        }

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openDefaultSearchEngineMenu()
            openAddSearchEngineMenu()
            verifySaveSearchEngineButtonEnabled(false)
            typeCustomEngineDetails(customSearchEngine.title, customSearchEngine.url)
            verifySaveSearchEngineButtonEnabled(true)
            saveNewSearchEngine()
            verifySnackBarText("Created ${customSearchEngine.title}")
            verifyEngineListContains(customSearchEngine.title, shouldExist = true)
            openEngineOverflowMenu(customSearchEngine.title)
            pressBack()
            changeDefaultSearchEngine(customSearchEngine.title)
            pressBack()
            openManageShortcutsMenu()
            verifyEngineListContains(customSearchEngine.title, shouldExist = true)
            pressBack()
        }.goBack {
            verifySettingsOptionSummary("Search", customSearchEngine.title)
        }.goBack {
        }.openSearch {
            verifySearchEngineIcon(customSearchEngine.title)
            clickSearchSelectorButton()
            verifySearchShortcutListContains(customSearchEngine.title)
        }
    }

    @Test
    fun addSearchEngineToManageShortcutsListTest() {
        val customSearchEngine = object {
            val title = "TestSearchEngine"
            val url = "http://localhost:${searchMockServer.port}/searchResults.html?search=%s"
        }

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openManageShortcutsMenu()
            openAddSearchEngineMenu()
            typeCustomEngineDetails(customSearchEngine.title, customSearchEngine.url)
            saveNewSearchEngine()
            verifyEngineListContains(customSearchEngine.title, shouldExist = true)
            pressBack()
            openDefaultSearchEngineMenu()
            verifyEngineListContains(customSearchEngine.title, shouldExist = true)
        }
    }

    @Test
    fun addSearchEngineLearnMoreLinksTest() {
        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openDefaultSearchEngineMenu()
            openAddSearchEngineMenu()
        }.clickCustomSearchStringLearnMoreLink {
            verifyUrl(
                "support.mozilla.org/en-US/kb/manage-my-default-search-engines-firefox-android?as=u&utm_source=inproduct",
            )
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openDefaultSearchEngineMenu()
            openAddSearchEngineMenu()
        }.clickCustomSearchSuggestionsLearnMoreLink {
            verifyUrl(
                "support.mozilla.org/en-US/kb/manage-my-default-search-engines-firefox-android?as=u&utm_source=inproduct",
            )
        }
    }

    @Test
    fun editCustomSearchEngineTest() {
        val customSearchEngine = object {
            val title = "TestSearchEngine"
            val url = "http://localhost:${searchMockServer.port}/searchResults.html?search=%s"
            val newTitle = "NewEngineTitle"
        }

        addCustomSearchEngine(searchMockServer, customSearchEngine.title)
        restartApp(activityTestRule.activityRule)

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openDefaultSearchEngineMenu()
            verifyEngineListContains(customSearchEngine.title, shouldExist = true)
            openEngineOverflowMenu(customSearchEngine.title)
            clickEdit()
            typeCustomEngineDetails(customSearchEngine.newTitle, customSearchEngine.url)
            saveEditSearchEngine()
            verifySnackBarText("Saved ${customSearchEngine.newTitle}")
            verifyEngineListContains(customSearchEngine.newTitle, shouldExist = true)
            pressBack()
            openManageShortcutsMenu()
            verifyEngineListContains(customSearchEngine.newTitle, shouldExist = true)
        }
    }

    @Ignore("Failing, see: https://bugzilla.mozilla.org/show_bug.cgi?id=1848623")
    @Test
    fun errorForInvalidSearchEngineStringsTest() {
        val customSearchEngine = object {
            val title = "TestSearchEngine"
            val badTemplateUrl = "http://localhost:${searchMockServer.port}/searchResults.html?search="
            val typoUrl = "http://local:${searchMockServer.port}/searchResults.html?search=%s"
            val goodUrl = "http://localhost:${searchMockServer.port}/searchResults.html?search=%s"
        }

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openDefaultSearchEngineMenu()
            openAddSearchEngineMenu()
            typeCustomEngineDetails(customSearchEngine.title, customSearchEngine.badTemplateUrl)
            saveNewSearchEngine()
            verifyInvalidTemplateSearchStringFormatError()
            typeCustomEngineDetails(customSearchEngine.title, customSearchEngine.typoUrl)
            saveNewSearchEngine()
            verifyErrorConnectingToSearchString(customSearchEngine.title)
            typeCustomEngineDetails(customSearchEngine.title, customSearchEngine.goodUrl)
            typeSearchEngineSuggestionString(customSearchEngine.badTemplateUrl)
            saveNewSearchEngine()
            verifyInvalidTemplateSearchStringFormatError()
            typeSearchEngineSuggestionString(customSearchEngine.typoUrl)
            saveNewSearchEngine()
            verifyErrorConnectingToSearchString(customSearchEngine.title)
        }
    }

    @Test
    fun deleteCustomSearchEngineTest() {
        val customSearchEngineTitle = "TestSearchEngine"

        addCustomSearchEngine(mockWebServer, searchEngineName = customSearchEngineTitle)
        restartApp(activityTestRule.activityRule)

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openDefaultSearchEngineMenu()
            verifyEngineListContains(customSearchEngineTitle, shouldExist = true)
            openEngineOverflowMenu(customSearchEngineTitle)
            clickDeleteSearchEngine()
            verifySnackBarText("Deleted $customSearchEngineTitle")
            clickUndoSnackBarButton()
            verifyEngineListContains(customSearchEngineTitle, shouldExist = true)
            changeDefaultSearchEngine(customSearchEngineTitle)
            openEngineOverflowMenu(customSearchEngineTitle)
            clickDeleteSearchEngine()
            verifyEngineListContains(customSearchEngineTitle, shouldExist = false)
            verifyDefaultSearchEngineSelected("Google")
            pressBack()
            openManageShortcutsMenu()
            verifyEngineListContains(customSearchEngineTitle, shouldExist = false)
            exitMenu()
        }
        searchScreen {
            clickSearchSelectorButton()
            verifySearchShortcutListContains(customSearchEngineTitle, shouldExist = false)
        }
    }

    @Test
    fun deleteCustomSearchShortcutTest() {
        val customSearchEngineTitle = "TestSearchEngine"

        addCustomSearchEngine(mockWebServer, searchEngineName = customSearchEngineTitle)
        restartApp(activityTestRule.activityRule)

        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openManageShortcutsMenu()
            verifyEngineListContains(customSearchEngineTitle, shouldExist = true)
            openCustomShortcutOverflowMenu(activityTestRule, customSearchEngineTitle)
            clickDeleteSearchEngine(activityTestRule)
            verifyEngineListContains(customSearchEngineTitle, shouldExist = false)
            pressBack()
            openDefaultSearchEngineMenu()
            verifyEngineListContains(customSearchEngineTitle, shouldExist = false)
            exitMenu()
        }
        searchScreen {
            clickSearchSelectorButton()
            verifySearchShortcutListContains(customSearchEngineTitle, shouldExist = false)
        }
    }

    // Test running on beta/release builds in CI:
    // caution when making changes to it, so they don't block the builds
    // Goes through the settings and changes the search suggestion toggle, then verifies it changes.
    @Ignore("Failing, see: https://github.com/mozilla-mobile/fenix/issues/23817")
    @SmokeTest
    @Test
    fun toggleSearchSuggestionsTest() {
        homeScreen {
        }.openSearch {
            typeSearch("mozilla ")
            verifySearchEngineSuggestionResults(
                activityTestRule,
                "mozilla firefox",
                searchTerm = "mozilla ",
            )
        }.dismissSearchBar {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            toggleShowSearchSuggestions()
        }.goBack {
        }.goBack {
        }.openSearch {
            typeSearch("mozilla")
            verifyNoSuggestionsAreDisplayed(activityTestRule, "mozilla firefox")
        }
    }

    // Tests the "Don't allow" option from private mode search suggestions onboarding dialog
    @Test
    fun blockSearchSuggestionsInPrivateModeOnboardingTest() {
        homeScreen {
            togglePrivateBrowsingModeOnOff()
        }.openSearch {
            typeSearch("mozilla")
            verifyAllowSuggestionsInPrivateModeDialog()
            denySuggestionsInPrivateMode()
            verifyNoSuggestionsAreDisplayed(activityTestRule, "mozilla firefox")
        }
    }

    // Tests the "Allow" option from private mode search suggestions onboarding dialog
    @Test
    fun allowSearchSuggestionsInPrivateModeOnboardingTest() {
        homeScreen {
            togglePrivateBrowsingModeOnOff()
        }.openSearch {
            typeSearch("mozilla")
            verifyAllowSuggestionsInPrivateModeDialog()
            allowSuggestionsInPrivateMode()
            verifySearchEngineSuggestionResults(
                activityTestRule,
                "mozilla firefox",
                searchTerm = "mozilla",
            )
        }.dismissSearchBar {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            switchShowSuggestionsInPrivateSessionsToggle()
        }.goBack {
        }.goBack {
        }.openSearch {
            typeSearch("mozilla")
            verifyNoSuggestionsAreDisplayed(activityTestRule, "mozilla firefox")
        }
    }

    @Test
    fun toggleVoiceSearchTest() {
        homeScreen {
        }.openSearch {
            verifyVoiceSearchButtonVisibility(true)
            startVoiceSearch()
        }.dismissSearchBar {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            toggleVoiceSearch()
            exitMenu()
        }
        homeScreen {
        }.openSearch {
            verifyVoiceSearchButtonVisibility(false)
        }
    }

    @Test
    fun toggleShowClipboardSuggestionsTest() {
        val link = "https://www.mozilla.org/en-US/"
        setTextToClipBoard(appContext, link)

        homeScreen {
        }.openNavigationToolbar {
            verifyClipboardSuggestionsAreDisplayed(link, true)
        }.visitLinkFromClipboard {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            verifyShowClipboardSuggestionsEnabled(true)
            toggleClipboardSuggestion()
            verifyShowClipboardSuggestionsEnabled(false)
            exitMenu()
        }
        homeScreen {
        }.openNavigationToolbar {
            verifyClipboardSuggestionsAreDisplayed(link, false)
        }
    }

    // Expected for app language set to Arabic
    @Test
    fun verifySearchEnginesWithRTLLocale() {
        val arabicLocale = Locale("ar", "AR")

        runWithSystemLocaleChanged(arabicLocale, activityTestRule.activityRule) {
            homeScreen {
            }.openSearch {
                verifyTranslatedFocusedNavigationToolbar("ابحث أو أدخِل عنوانا")
                clickSearchSelectorButton()
                verifySearchShortcutListContains(
                    "Google",
                    "Bing",
                    "Amazon.com",
                    "DuckDuckGo",
                    "ويكيبيديا (ar)",
                )
                selectTemporarySearchMethod("ويكيبيديا (ar)")
            }.submitQuery("firefox") {
                verifyUrl("firefox")
            }
        }
    }

    @Test
    fun searchEnginesListRespectLocaleTest() {
        runWithSystemLocaleChanged(Locale.CHINA, activityTestRule.activityRule) {
            // Checking search engines for CH locale
            homeScreen {
            }.openSearch {
                clickSearchSelectorButton()
                verifySearchShortcutListContains(
                    "Google",
                    "百度",
                    "Bing",
                    "DuckDuckGo",
                )
            }.dismissSearchBar {}

            // Checking search engines for FR locale
            setSystemLocale(Locale.FRENCH)
            homeScreen {
            }.openSearch {
                clickSearchSelectorButton()
                verifySearchShortcutListContains(
                    "Google",
                    "Bing",
                    "DuckDuckGo",
                    "Qwant",
                    "Wikipédia (fr)",
                )
            }
        }
    }

    @Test
    fun manageSearchShortcutsSettingsItemsTest() {
        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openManageShortcutsMenu()
            verifyToolbarText("Manage search shortcuts")
            verifyEnginesShortcutsListHeader()
            verifyManageShortcutsList(activityTestRule)
            verifySearchShortcutChecked(
                EngineShortcut(name = "Google", checkboxIndex = 1, isChecked = true),
                EngineShortcut(name = "Bing", checkboxIndex = 4, isChecked = true),
                EngineShortcut(name = "Amazon.com", checkboxIndex = 7, isChecked = true),
                EngineShortcut(name = "DuckDuckGo", checkboxIndex = 10, isChecked = true),
                EngineShortcut(name = "eBay", checkboxIndex = 13, isChecked = true),
                EngineShortcut(name = "Wikipedia", checkboxIndex = 16, isChecked = true),
                EngineShortcut(name = "Reddit", checkboxIndex = 19, isChecked = false),
                EngineShortcut(name = "YouTube", checkboxIndex = 22, isChecked = false),
            )
        }
    }

    @SmokeTest
    @Test
    fun changeSearchShortcutsListTest() {
        homeScreen {
        }.openThreeDotMenu {
        }.openSettings {
        }.openSearchSubMenu {
            openManageShortcutsMenu()
            selectSearchShortcut(EngineShortcut(name = "Google", checkboxIndex = 1))
            selectSearchShortcut(EngineShortcut(name = "Amazon.com", checkboxIndex = 7))
            selectSearchShortcut(EngineShortcut(name = "Reddit", checkboxIndex = 19))
            selectSearchShortcut(EngineShortcut(name = "YouTube", checkboxIndex = 22))
            exitMenu()
        }
        searchScreen {
            clickSearchSelectorButton()
            verifySearchShortcutListContains("Google", "Amazon.com", shouldExist = false)
            verifySearchShortcutListContains("YouTube", shouldExist = true)
            verifySearchShortcutListContains("Reddit", shouldExist = true)
        }
    }
}
