package com.yorvana.regression.billing

import androidx.compose.ui.test.ComposeTimeoutException
import androidx.compose.ui.test.assertIsDisplayed
import androidx.compose.ui.test.junit4.createAndroidComposeRule
import androidx.compose.ui.test.onNodeWithTag
import androidx.compose.ui.test.onNodeWithText
import androidx.compose.ui.test.performClick
import androidx.compose.ui.test.performScrollTo
import androidx.test.ext.junit.runners.AndroidJUnit4
import com.google.common.truth.Truth.assertThat
import com.yorvana.MainActivity
import com.yorvana.R
import com.yorvana.data.billing.DebugBillingActions
import com.yorvana.testsupport.BillingSandboxEnvironment
import com.yorvana.testsupport.RetryRule
import com.yorvana.testsupport.app
import com.yorvana.testsupport.awaitTagGone
import com.yorvana.testsupport.awaitText
import com.yorvana.testsupport.installFreshVault
import com.yorvana.testsupport.resetYorvanaState
import com.yorvana.testsupport.seedVehicle
import com.yorvana.testsupport.tiers.BillingSandbox
import com.yorvana.testsupport.tiers.ScenarioId
import com.yorvana.ui.TestTags
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import org.junit.rules.RuleChain
import org.junit.runner.RunWith

@BillingSandbox
@RunWith(AndroidJUnit4::class)
class BillingSandboxRegressionTest {
    val retryRule = RetryRule()
    val composeRule = createAndroidComposeRule<MainActivity>()

    @get:Rule
    val ruleChain: RuleChain = RuleChain.outerRule(retryRule).around(composeRule)

    @Before
    fun setUp() {
        BillingSandboxEnvironment.assumeReady()
        composeRule.resetYorvanaState()
        composeRule.installFreshVault()
        runBlocking { (composeRule.app().billingManager as? DebugBillingActions)?.resetBillingState() }
    }

    @After
    fun tearDown() {
        composeRule.resetYorvanaState()
    }

    /**
     * R-P03 is a manually triggered sandbox smoke. `premium_lifetime` is a non-consumable
     * product, so the license-tester entitlement must be refunded/revoked in Play Console
     * before each purchase run; scheduled billing sandbox runs execute R-P04 only.
     */
    @Test
    fun rP03_realPurchaseFromAtCapFab_activatesPremiumAndNavigatesToAddVehicle() {
        BillingSandboxEnvironment.assumeScenario("purchase")

        composeRule.seedVehicle(nickname = "Sandbox Free Car")
        composeRule.onNodeWithTag(TestTags.ADD_VEHICLE_FAB).performClick()
        composeRule.awaitText(composeRule.activity.getString(R.string.paywall_sheet_headline))
        composeRule.onNodeWithText(composeRule.activity.getString(R.string.paywall_sheet_cta)).performClick()

        BillingSandboxEnvironment.completePurchaseFlow()

        awaitPremiumEntitlement("Purchase")
        composeRule.awaitTagGone(TestTags.PAYWALL_INFO_SHEET, timeoutMillis = 60_000)
        composeRule.awaitText(composeRule.activity.getString(R.string.vehicle_add), timeoutMillis = 60_000)
        assertThat(
            runBlocking {
                composeRule
                    .app()
                    .preferences
                    .preferences
                    .first()
                    .isPremiumCached
            },
        ).isTrue()
    }

    @ScenarioId("R-P04")
    @Test
    fun rP04_restorePurchaseFromFreshAppData_flipsPremiumAndRerendersSettings() {
        BillingSandboxEnvironment.assumeScenario("restore")

        assertThat(
            runBlocking {
                composeRule
                    .app()
                    .billingManager
                    .isPremium
                    .first()
            },
        ).isFalse()

        openSettings()
        composeRule
            .onNodeWithText(composeRule.activity.getString(R.string.restore_button))
            .performScrollTo()
            .performClick()

        awaitPremiumEntitlement("Restore")
        composeRule
            .onNodeWithText(composeRule.activity.getString(R.string.premium_active_title))
            .performScrollTo()
            .assertIsDisplayed()
    }

    private fun openSettings() {
        composeRule.onNodeWithTag(TestTags.SETTINGS_BUTTON).performClick()
        composeRule.awaitText(composeRule.activity.getString(R.string.settings_title))
    }

    private fun awaitPremiumEntitlement(action: String) {
        try {
            composeRule.waitUntil(60_000) {
                runBlocking {
                    composeRule
                        .app()
                        .billingManager
                        .isPremium
                        .first()
                }
            }
        } catch (e: ComposeTimeoutException) {
            throw AssertionError(
                "$action did not mark premium within 60s. " +
                    "Play purchase snapshot: ${BillingSandboxEnvironment.purchaseSnapshot()}",
                e,
            )
        }
    }
}
