/* 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.addons.migration

import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.work.Configuration
import androidx.work.WorkInfo
import androidx.work.WorkManager
import androidx.work.await
import androidx.work.testing.WorkManagerTestInitHelper
import junit.framework.TestCase.assertEquals
import junit.framework.TestCase.assertFalse
import junit.framework.TestCase.assertTrue
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker.Companion.WORK_TAG_PERIODIC
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker.Companion.CHECKER_UNIQUE_PERIODIC_WORK_NAME
import mozilla.components.feature.addons.migration.SupportedAddonsChecker.Frequency
import mozilla.components.support.test.mock
import mozilla.components.support.test.robolectric.testContext
import mozilla.components.support.test.rule.MainCoroutineRule
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.ArgumentMatchers
import org.mockito.Mockito.doReturn
import org.mockito.Mockito.spy
import java.util.concurrent.TimeUnit

@RunWith(AndroidJUnit4::class)
class DefaultSupportedAddonCheckerTest {

    @ExperimentalCoroutinesApi
    @get:Rule
    val coroutinesTestRule = MainCoroutineRule()

    lateinit var context: Context

    @Before
    fun setUp() {
        val configuration = Configuration.Builder().build()
        context = spy(testContext).also {
            val packageManager: PackageManager = mock()
            doReturn(Intent()).`when`(packageManager).getLaunchIntentForPackage(
                    ArgumentMatchers.anyString()
            )
            doReturn(packageManager).`when`(it).packageManager
        }

        // Initialize WorkManager (early) for instrumentation tests.
        WorkManagerTestInitHelper.initializeTestWorkManager(testContext, configuration)
        SupportedAddonsWorker.onNotificationClickIntent = Intent()
    }

    @Test
    fun `registerForChecks - schedule work for future checks`() {
        val frequency = Frequency(1, TimeUnit.DAYS)
        val intent = Intent()
        val checker = DefaultSupportedAddonsChecker(context, frequency, intent)

        val workId = CHECKER_UNIQUE_PERIODIC_WORK_NAME

        runBlocking {
            val workManger = WorkManager.getInstance(testContext)
            val workData = workManger.getWorkInfosForUniqueWork(workId).await()

            assertTrue(workData.isEmpty())

            checker.registerForChecks()

            assertExtensionIsRegisteredForChecks()
            assertEquals(intent, SupportedAddonsWorker.onNotificationClickIntent)
            // Cleaning work manager
            workManger.cancelUniqueWork(workId)
        }
    }

    @Test
    fun `unregisterForChecks - will remove scheduled work for future checks`() {
        val frequency = Frequency(1, TimeUnit.DAYS)
        val checker = DefaultSupportedAddonsChecker(context, frequency)

        val workId = CHECKER_UNIQUE_PERIODIC_WORK_NAME

        runBlocking {
            val workManger = WorkManager.getInstance(testContext)
            var workData = workManger.getWorkInfosForUniqueWork(workId).await()

            assertTrue(workData.isEmpty())

            checker.registerForChecks()

            assertExtensionIsRegisteredForChecks()

            checker.unregisterForChecks()

            workData = workManger.getWorkInfosForUniqueWork(workId).await()

            assertEquals(WorkInfo.State.CANCELLED, workData.first().state)
        }
    }

    private suspend fun assertExtensionIsRegisteredForChecks() {
        val workId = CHECKER_UNIQUE_PERIODIC_WORK_NAME
        val workManger = WorkManager.getInstance(testContext)
        val workData = workManger.getWorkInfosForUniqueWork(workId).await()

        assertFalse(workData.isEmpty())

        val work = workData.first()

        assertEquals(WorkInfo.State.ENQUEUED, work.state)
        assertTrue(work.tags.contains(workId))
        assertTrue(work.tags.contains(WORK_TAG_PERIODIC))
    }
}
