package eu.darken.bluemusic.upgrade.ui

import androidx.activity.ComponentActivity
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.lifecycle.Lifecycle
import eu.darken.bluemusic.common.compose.PreviewWrapper
import eu.darken.bluemusic.upgrade.core.UpgradeRepoGplay
import eu.darken.bluemusic.upgrade.core.billing.GplayServiceUnavailableException
import eu.darken.bluemusic.upgrade.core.billing.Sku
import io.mockk.coEvery
import io.mockk.every
import io.mockk.mockk
import kotlinx.coroutines.flow.MutableStateFlow
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.robolectric.RobolectricTestRunner
import org.robolectric.annotation.Config
import testhelpers.BaseTest
import testhelpers.TestApplication
import testhelpers.coroutine.TestDispatcherProvider

/**
 * Host-level counterpart to the ViewModel's `onResume` tests: those prove the ViewModel re-queries,
 * they cannot prove the screen actually asks it to. Only a real lifecycle round-trip catches a
 * missing or mis-scoped ON_RESUME effect.
 */
@RunWith(RobolectricTestRunner::class)
@Config(sdk = [33], application = TestApplication::class)
class GplayUpgradeScreenHostTest : BaseTest() {

    @get:Rule
    val composeRule = createAndroidComposeRule<ComponentActivity>()

    private fun mockRepo(): UpgradeRepoGplay = mockk<UpgradeRepoGplay>(relaxed = true).apply {
        every { upgradeInfo } returns MutableStateFlow(UpgradeRepoGplay.Info(false, null, null, isSettled = true))
        every { wasEverPro } returns MutableStateFlow(false)
        every { proUnconfirmedSince } returns MutableStateFlow(0L)
        every { autoRestoreBusy } returns MutableStateFlow(false)
        every { purchaseLaunchSku } returns MutableStateFlow<Sku?>(null)
    }

    @Test
    fun `returning to the screen re-runs a failed offers query`() {
        val repo = mockRepo()
        var queries = 0
        coEvery { repo.querySkus(any()) } coAnswers {
            queries++
            throw GplayServiceUnavailableException(RuntimeException("Play hiccup"))
        }
        // The AssistedInject constructor is callable directly: hiltViewModel() has nothing to
        // resolve here, so the real ViewModel instance is passed explicitly.
        val vm = UpgradeViewModel(
            manage = false,
            dispatcherProvider = TestDispatcherProvider(),
            navCtrl = mockk(relaxed = true),
            upgradeRepo = repo,
            webpageTool = mockk(relaxed = true),
        )

        composeRule.setContent {
            PreviewWrapper {
                UpgradeScreenHost(manage = false, vm = vm)
            }
        }

        composeRule.waitUntil { vm.state.value is GplayUpgradeUiState.Unavailable }
        val baseline = queries

        composeRule.activityRule.scenario.moveToState(Lifecycle.State.STARTED)
        composeRule.activityRule.scenario.moveToState(Lifecycle.State.RESUMED)
        composeRule.waitForIdle()

        composeRule.waitUntil { queries > baseline }
    }
}
