/* 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.tabstray

import android.content.Context
import androidx.navigation.NavController
import io.mockk.Runs
import io.mockk.every
import io.mockk.just
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import mozilla.components.browser.state.state.ContentState
import mozilla.components.browser.state.state.TabSessionState
import mozilla.components.support.test.robolectric.testContext
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mozilla.fenix.NavGraphDirections
import org.mozilla.fenix.helpers.FenixGleanTestRule
import org.mozilla.fenix.helpers.MockkRetryTestRule
import org.mozilla.fenix.home.HomeScreenViewModel
import org.mozilla.fenix.navigation.NavControllerProvider
import org.mozilla.fenix.tabstray.ui.TabManagementFragment
import org.robolectric.RobolectricTestRunner

@RunWith(RobolectricTestRunner::class)
class TabManagementFragmentTest {
    private lateinit var context: Context
    private lateinit var fragment: TabManagementFragment

    @get:Rule
    val mockkRule = MockkRetryTestRule()

    @get:Rule
    val gleanTestRule = FenixGleanTestRule(testContext)

    @Before
    fun setup() {
        context = mockk(relaxed = true)

        fragment = spyk(TabManagementFragment())
        every { fragment.context } returns context
        every { fragment.viewLifecycleOwner } returns mockk(relaxed = true)
        every { fragment.view } returns mockk()
    }

    @Test
    fun `WHEN navigateToHomeAndDeleteSession is called with a sessionId THEN it navigates to home and transmits there the sessionId`() {
        val viewModel: HomeScreenViewModel = mockk(relaxed = true)
        every { fragment.homeViewModel } returns viewModel
        val navController: NavController = mockk(relaxed = true)

        val navControllerProvider: NavControllerProvider = mockk()
        every { navControllerProvider.getNavController(fragment) } returns navController

        fragment.navigateToHomeAndDeleteSession(
            "test",
            navControllerProvider = navControllerProvider,
        )

        verify { viewModel.sessionToDelete = "test" }
        verify { navController.navigate(NavGraphDirections.actionGlobalHome()) }
    }

    @Test
    fun `WHEN dismissTabManager is called THEN it dismisses the tab manager`() {
        val navController: NavController = mockk(relaxed = true)
        every { fragment.recordBreadcrumb(any()) } just Runs

        fragment.dismissTabManager(navController = navController)

        verify { navController.popBackStack() }
    }

    @Test
    fun `GIVEN a list of tabs WHEN a tab is present with an ID THEN the index is returned`() {
        val tab1 = TabSessionState(
            id = "tab1",
            content = ContentState(
                url = "https://mozilla.org",
                private = false,
            ),
        )
        val tab2 = TabSessionState(
            id = "tab2",
            content = ContentState(
                url = "https://mozilla.org",
                private = false,
            ),
        )
        val tab3 = TabSessionState(
            id = "tab3",
            content = ContentState(
                url = "https://mozilla.org",
                private = false,
            ),
        )
        val tabsList = listOf(
            tab1,
            tab2,
            tab3,
        )
        val position = fragment.getTabPositionFromId(tabsList, "tab2")
        assertEquals(1, position)
    }

    @Test
    fun `WHEN all conditions are met THEN shouldShowLockPbmBanner returns true`() {
        val result = testShouldShowLockPbmBanner()
        assertTrue(result)
    }

    @Test
    fun `WHEN isPrivateMode is false THEN shouldShowLockPbmBanner returns false`() {
        val result = testShouldShowLockPbmBanner(isPrivateMode = false)
        assertFalse(result)
    }

    @Test
    fun `WHEN hasPrivateTabs is false THEN shouldShowLockPbmBanner returns false`() {
        val result = testShouldShowLockPbmBanner(hasPrivateTabs = false)
        assertFalse(result)
    }

    @Test
    fun `WHEN biometricAvailable is false THEN shouldShowLockPbmBanner returns false`() {
        val result = testShouldShowLockPbmBanner(biometricAvailable = false)
        assertFalse(result)
    }

    @Test
    fun `WHEN privateLockEnabled is true THEN shouldShowLockPbmBanner returns false`() {
        val result = testShouldShowLockPbmBanner(privateLockEnabled = true)
        assertFalse(result)
    }

    @Test
    fun `WHEN shouldShowBanner is false THEN shouldShowLockPbmBanner returns false`() {
        val result = testShouldShowLockPbmBanner(shouldShowBanner = false)
        assertFalse(result)
    }

    private fun testShouldShowLockPbmBanner(
        isPrivateMode: Boolean = true,
        hasPrivateTabs: Boolean = true,
        biometricAvailable: Boolean = true,
        privateLockEnabled: Boolean = false,
        shouldShowBanner: Boolean = true,
    ): Boolean {
        return fragment.shouldShowLockPbmBanner(
            isPrivateMode = isPrivateMode,
            hasPrivateTabs = hasPrivateTabs,
            biometricAvailable = biometricAvailable,
            privateLockEnabled = privateLockEnabled,
            shouldShowBanner = shouldShowBanner,
        )
    }
}
