/*
 * 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 mozilla.components.feature.session

import android.app.Activity
import android.content.pm.PackageManager
import android.os.Build
import mozilla.components.browser.session.Session
import mozilla.components.browser.session.SessionManager
import mozilla.components.support.test.any
import mozilla.components.support.test.mock
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.never
import org.mockito.Mockito.spy
import org.mockito.Mockito.verify
import org.mockito.Mockito.verifyNoMoreInteractions
import org.mockito.Mockito.verifyZeroInteractions
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config

private interface PipChangedCallback : (Boolean) -> Unit

@RunWith(RobolectricTestRunner::class)
class PictureInPictureFeatureTest {
    private val sessionManager: SessionManager = mock()
    private val selectedSession: Session = mock()
    private val activity: Activity = Mockito.mock(Activity::class.java, Mockito.RETURNS_DEEP_STUBS)

    @Before
    fun setUp() {
        `when`(activity.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE))
            .thenReturn(true)
    }

    @Test
    @Config(sdk = [Build.VERSION_CODES.M])
    fun `on home pressed without system feature on android m and lower`() {
        `when`(activity.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE))
            .thenReturn(false)

        val pictureInPictureFeature = spy(PictureInPictureFeature(sessionManager, activity))

        assertFalse(pictureInPictureFeature.onHomePressed())
        verifyZeroInteractions(sessionManager)
        verifyZeroInteractions(activity.packageManager)
        verify(pictureInPictureFeature, never()).enterPipModeCompat()
    }

    @Test
    @Config(sdk = [Build.VERSION_CODES.N])
    fun `on home pressed without system feature on android n and above`() {
        `when`(activity.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE))
            .thenReturn(false)

        val pictureInPictureFeature = spy(PictureInPictureFeature(sessionManager, activity))

        assertFalse(pictureInPictureFeature.onHomePressed())
        verifyZeroInteractions(sessionManager)
        verify(activity.packageManager).hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
        verify(pictureInPictureFeature, never()).enterPipModeCompat()
    }

    @Test
    fun `on home pressed without a selected session`() {
        val pictureInPictureFeature = spy(PictureInPictureFeature(sessionManager, activity))

        assertFalse(pictureInPictureFeature.onHomePressed())
        verify(sessionManager).selectedSession
        verify(activity.packageManager).hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE)
        verify(pictureInPictureFeature, never()).enterPipModeCompat()
    }

    @Test
    fun `on home pressed with a selected session without a fullscreen mode`() {
        val pictureInPictureFeature = spy(PictureInPictureFeature(sessionManager, activity))

        `when`(selectedSession.fullScreenMode).thenReturn(false)
        `when`(sessionManager.selectedSession).thenReturn(selectedSession)

        assertFalse(pictureInPictureFeature.onHomePressed())
        verify(sessionManager).selectedSession
        verify(selectedSession).fullScreenMode
        verify(pictureInPictureFeature, never()).enterPipModeCompat()
    }

    @Test
    fun `on home pressed with a selected session in fullscreen and without pip mode`() {
        val pictureInPictureFeature = spy(PictureInPictureFeature(sessionManager, activity))

        `when`(selectedSession.fullScreenMode).thenReturn(true)
        `when`(sessionManager.selectedSession).thenReturn(selectedSession)
        doReturn(false).`when`(pictureInPictureFeature).enterPipModeCompat()

        assertFalse(pictureInPictureFeature.onHomePressed())
        verify(sessionManager).selectedSession
        verify(selectedSession).fullScreenMode
        verify(pictureInPictureFeature).enterPipModeCompat()
    }

    @Test
    fun `on home pressed with a selected session in fullscreen and with pip mode`() {
        val pictureInPictureFeature = spy(PictureInPictureFeature(sessionManager, activity))

        `when`(selectedSession.fullScreenMode).thenReturn(true)
        `when`(sessionManager.selectedSession).thenReturn(selectedSession)
        doReturn(true).`when`(pictureInPictureFeature).enterPipModeCompat()

        assertTrue(pictureInPictureFeature.onHomePressed())
        verify(sessionManager).selectedSession
        verify(selectedSession).fullScreenMode
        verify(pictureInPictureFeature).enterPipModeCompat()
    }

    @Test
    @Config(sdk = [Build.VERSION_CODES.M])
    fun `enter pip mode compat on android m and below`() {
        val pictureInPictureFeature = PictureInPictureFeature(sessionManager, activity)

        assertFalse(pictureInPictureFeature.enterPipModeCompat())
    }

    @Test
    @Config(sdk = [Build.VERSION_CODES.O])
    fun `enter pip mode compat without system feature on android o`() {
        `when`(activity.packageManager.hasSystemFeature(PackageManager.FEATURE_PICTURE_IN_PICTURE))
            .thenReturn(false)

        val pictureInPictureFeature = PictureInPictureFeature(sessionManager, activity)

        assertFalse(pictureInPictureFeature.enterPipModeCompat())
        verify(activity, never()).enterPictureInPictureMode(any())
        verify(activity, never()).enterPictureInPictureMode()
    }

    @Test
    @Config(sdk = [Build.VERSION_CODES.O])
    fun `enter pip mode compat on android o and above`() {
        val pictureInPictureFeature = PictureInPictureFeature(sessionManager, activity)

        `when`(activity.enterPictureInPictureMode(any())).thenReturn(true)

        assertTrue(pictureInPictureFeature.enterPipModeCompat())
        verify(activity).enterPictureInPictureMode(any())
    }

    @Test
    @Config(sdk = [Build.VERSION_CODES.N])
    fun `enter pip mode compat on android n and above`() {
        val pictureInPictureFeature = PictureInPictureFeature(sessionManager, activity)

        assertTrue(pictureInPictureFeature.enterPipModeCompat())
        verify(activity).enterPictureInPictureMode()
    }

    @Test
    fun `on pip mode changed`() {
        val pipChangedCallback: PipChangedCallback = mock()
        val pipFeature = PictureInPictureFeature(sessionManager, activity, pipChangedCallback)

        pipFeature.onPictureInPictureModeChanged(true)
        verify(pipChangedCallback).invoke(true)

        pipFeature.onPictureInPictureModeChanged(false)
        verify(pipChangedCallback).invoke(false)

        verifyNoMoreInteractions(sessionManager)
        verify(activity, never()).enterPictureInPictureMode(any())
        verify(activity, never()).enterPictureInPictureMode()
    }
}
