package app.closer.data.repository

import android.app.Activity
import android.app.Application
import app.closer.BuildConfig
import app.closer.core.billing.EntitlementChecker
import app.closer.domain.repository.BillingRepository
import app.closer.domain.repository.BillingState
import com.revenuecat.purchases.CustomerInfo
import com.revenuecat.purchases.LogLevel
import com.revenuecat.purchases.Offerings
import com.revenuecat.purchases.Package
import com.revenuecat.purchases.Purchases
import com.revenuecat.purchases.PurchasesConfiguration
import com.revenuecat.purchases.PurchaseResult
import com.revenuecat.purchases.PurchaseParams
import com.revenuecat.purchases.awaitOfferings
import com.revenuecat.purchases.awaitPurchase
import com.revenuecat.purchases.awaitRestore
import javax.inject.Inject
import javax.inject.Singleton
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow

/**
 * RevenueCat-backed implementation of [BillingRepository].
 *
 * - Initializes Purchases once per process with the API key from BuildConfig.
 * - Uses RevenueCat Kotlin coroutine extensions where available.
 * - Maps RevenueCat results to [BillingState] for stable UI contracts.
 *
 * Note: A real app must set a valid Google Play API key in BuildConfig or local
 * config. The placeholder key here is sufficient for wiring and compilation.
 */
@Singleton
class RevenueCatBillingRepository @Inject constructor(
    private val application: Application,
    private val entitlementChecker: EntitlementChecker
) : BillingRepository {

    init {
        if (!Purchases.isConfigured) {
            Purchases.logLevel = if (BuildConfig.DEBUG) LogLevel.DEBUG else LogLevel.INFO
            Purchases.configure(
                PurchasesConfiguration.Builder(application, BuildConfig.RC_API_KEY).build()
            )
        }
    }

    override suspend fun getOfferings(): BillingState<Offerings> = runCatching {
        BillingState.Success(Purchases.sharedInstance.awaitOfferings())
    }.getOrElse { BillingState.Error(it.localizedMessage ?: "Could not load offerings") }

    override suspend fun purchasePackage(pkg: Package): BillingState<PurchaseResult> = runCatching {
        BillingState.Success(
            Purchases.sharedInstance.awaitPurchase(
                PurchaseParams.Builder(getActivity(), pkg).build()
            )
        )
    }.getOrElse { BillingState.Error(it.localizedMessage ?: "Purchase failed") }

    override suspend fun restorePurchases(): BillingState<CustomerInfo> = runCatching {
        BillingState.Success(Purchases.sharedInstance.awaitRestore())
    }.getOrElse { BillingState.Error(it.localizedMessage ?: "Restore failed") }

    override fun getCustomerInfo(): Flow<BillingState<CustomerInfo>> = callbackFlow {
        trySend(BillingState.Loading)
        val listener = object : com.revenuecat.purchases.interfaces.UpdatedCustomerInfoListener {
            override fun onReceived(customerInfo: CustomerInfo) {
                entitlementChecker.onCustomerInfoUpdated(customerInfo)
                trySend(BillingState.Success(customerInfo))
            }
        }
        Purchases.sharedInstance.updatedCustomerInfoListener = listener
        awaitClose {
            Purchases.sharedInstance.updatedCustomerInfoListener = null
        }
    }

    /**
     * RevenueCat purchases require an [Activity] reference. The repository stores
     * the Application context and casts the first resumed Activity from a small
     * internal tracker. This keeps the repository testable and lifecycle-agnostic
     * while satisfying RevenueCat's purchase API.
     */
    private fun getActivity(): Activity {
        return ActivityProvider.currentActivity
            ?: throw IllegalStateException("No active Activity available for purchase")
    }
}
