package com.bigcrunch.ads import android.app.Activity import android.content.Context import com.bigcrunch.ads.adapters.GoogleAdsAdapter import com.bigcrunch.ads.core.AdOrchestrator import com.bigcrunch.ads.core.RewardedCallback import com.bigcrunch.ads.internal.BCLogger import com.bigcrunch.ads.listeners.RewardedAdListener /** * BigCrunch Rewarded Ads - Static API for rewarded video ads * * Rewarded ads are full-screen video ads that reward users for watching. * Users have the option to watch the ad in exchange for in-app rewards. * * Usage: * ```kotlin * // 1. Preload the ad * BigCrunchRewarded.preload( * context = applicationContext, * placementId = "daily_reward", * callback = object : BigCrunchRewarded.PreloadCallback { * override fun onAdLoaded() { /* ad ready to show */ } * override fun onAdFailedToLoad(error: String) { /* handle error */ } * } * ) * * // 2. Check if ready * if (BigCrunchRewarded.isReady("daily_reward")) { * // Ad is ready to show * } * * // 3. Show when user requests * BigCrunchRewarded.show( * activity = this, * placementId = "daily_reward", * callback = object : BigCrunchRewarded.ShowCallback { * override fun onUserEarnedReward(type: String, amount: Int) { * // Give user their reward * } * override fun onAdDismissed() { /* ad closed */ } * override fun onAdFailedToShow(error: String) { /* handle error */ } * } * ) * ``` */ object BigCrunchRewarded { private val TAG = "BigCrunchRewarded" private var adOrchestrator: AdOrchestrator? = null private val orchestratorLock = Any() // Listeners for React Native compatibility private val listeners = mutableMapOf() /** * Callback interface for preloading rewarded ads */ interface PreloadCallback { /** * Called when the ad has been successfully loaded and is ready to show */ fun onAdLoaded() /** * Called when the ad fails to load * @param error Description of what went wrong */ fun onAdFailedToLoad(error: String) } /** * Callback interface for showing rewarded ads */ interface ShowCallback { /** * Called when the user has earned a reward by watching the ad * @param type The type of reward (e.g., "coins", "points") * @param amount The amount of reward earned */ fun onUserEarnedReward(type: String, amount: Int) /** * Called when the ad is dismissed (whether reward was earned or not) */ fun onAdDismissed() /** * Called when the ad was shown successfully */ fun onAdShowed() {} /** * Called when the user clicks on the ad */ fun onAdClicked() {} /** * Called when the ad fails to show * @param error Description of what went wrong */ fun onAdFailedToShow(error: String) } /** * Combined callback interface (for compatibility) */ interface Callback : PreloadCallback, ShowCallback /** * Preload a rewarded ad with callback * * @param context Application or Activity context * @param placementId The placement ID from BigCrunch dashboard * @param callback Callback for load events */ fun preload( context: Context, placementId: String, callback: PreloadCallback? = null ) { BCLogger.d(TAG, "Preloading rewarded ad: $placementId") try { BigCrunchAds.requireInitialized() } catch (e: IllegalStateException) { BCLogger.e(TAG, "SDK not initialized", e) callback?.onAdFailedToLoad("SDK not initialized") return } val orchestrator = getOrCreateOrchestrator(context) // Create internal callback val rewardedCallback = object : RewardedCallback { override fun onAdLoaded() { BCLogger.d(TAG, "Rewarded ad loaded: $placementId") callback?.onAdLoaded() listeners[placementId]?.onAdLoaded() } override fun onAdFailedToLoad(error: String) { BCLogger.w(TAG, "Rewarded ad failed to load: $placementId - $error") callback?.onAdFailedToLoad(error) listeners[placementId]?.onAdFailedToLoad("LOAD_ERROR", error) } override fun onAdShowed() { BCLogger.d(TAG, "Rewarded ad showed: $placementId") listeners[placementId]?.onAdShowed() } override fun onAdDismissed() { BCLogger.d(TAG, "Rewarded ad dismissed: $placementId") listeners[placementId]?.onAdDismissed() } override fun onAdClicked() { BCLogger.d(TAG, "Rewarded ad clicked: $placementId") listeners[placementId]?.onAdClicked() } override fun onUserEarnedReward(type: String, amount: Int) { BCLogger.d(TAG, "User earned reward: $type x$amount for $placementId") listeners[placementId]?.onUserEarnedReward(type, amount) } } // Load through AdOrchestrator orchestrator.preloadRewardedAd(placementId, rewardedCallback) } /** * Preload a rewarded ad without callback * * @param placementId The placement ID from BigCrunch dashboard */ fun preload(placementId: String) { // Need context from somewhere - could get from last show() call BCLogger.w(TAG, "Preload called without context - not implemented") } /** * Load a rewarded ad with custom targeting * * @param placementId The placement ID for the ad * @param customTargeting Optional custom targeting parameters */ fun load(placementId: String, customTargeting: Map? = null) { BCLogger.d(TAG, "Loading rewarded ad: $placementId") if (customTargeting != null) { BCLogger.d(TAG, "Custom targeting requested: ${customTargeting.size} parameters") } // Need context - could store from initialization preload(placementId) } /** * Show a preloaded rewarded ad * * @param activity The activity to show the ad in * @param placementId The placement ID * @param callback Callback for ad events * @return true if the ad was shown, false if not ready */ fun show( activity: Activity, placementId: String, callback: ShowCallback? = null ): Boolean { BCLogger.d(TAG, "Attempting to show rewarded ad: $placementId") try { BigCrunchAds.requireInitialized() } catch (e: IllegalStateException) { BCLogger.e(TAG, "SDK not initialized", e) callback?.onAdFailedToShow("SDK not initialized") listeners[placementId]?.onAdFailedToLoad("SDK_NOT_INITIALIZED", "SDK not initialized") return false } if (!isReady(placementId)) { val error = "Rewarded ad not ready: $placementId" BCLogger.w(TAG, error) callback?.onAdFailedToShow(error) listeners[placementId]?.onAdFailedToLoad("NOT_READY", error) return false } val orchestrator = getOrCreateOrchestrator(activity) // Create internal callback val rewardedCallback = object : RewardedCallback { override fun onAdLoaded() { // Not used during show } override fun onAdFailedToLoad(error: String) { BCLogger.w(TAG, "Rewarded ad failed to show: $placementId - $error") callback?.onAdFailedToShow(error) listeners[placementId]?.onAdFailedToLoad("SHOW_ERROR", error) } override fun onAdShowed() { BCLogger.d(TAG, "Rewarded ad showed: $placementId") callback?.onAdShowed() listeners[placementId]?.onAdShowed() } override fun onAdDismissed() { BCLogger.d(TAG, "Rewarded ad dismissed: $placementId") callback?.onAdDismissed() listeners[placementId]?.onAdDismissed() } override fun onAdClicked() { BCLogger.d(TAG, "Rewarded ad clicked: $placementId") callback?.onAdClicked() listeners[placementId]?.onAdClicked() } override fun onUserEarnedReward(type: String, amount: Int) { BCLogger.d(TAG, "User earned reward: $type x$amount for $placementId") callback?.onUserEarnedReward(type, amount) listeners[placementId]?.onUserEarnedReward(type, amount) } } return orchestrator.showRewardedAd(activity, placementId, rewardedCallback) } /** * Show a preloaded rewarded ad with listener * * @param activity The activity to show the ad in * @param placementId The placement ID * @param listener Listener for ad events * @return true if the ad was shown, false if not ready */ fun show( activity: Activity, placementId: String, listener: RewardedAdListener? = null ): Boolean { if (listener != null) { listeners[placementId] = listener } // Convert listener to callback val callback = if (listener != null) { object : ShowCallback { override fun onUserEarnedReward(type: String, amount: Int) { listener.onUserEarnedReward(type, amount) } override fun onAdDismissed() { listener.onAdDismissed() } override fun onAdShowed() { listener.onAdShowed() } override fun onAdClicked() { listener.onAdClicked() } override fun onAdFailedToShow(error: String) { listener.onAdFailedToLoad("SHOW_ERROR", error) } } } else null return show(activity, placementId, callback) } /** * Check if a rewarded ad is ready to show * * @param placementId The placement ID * @return true if ad is loaded and ready */ fun isReady(placementId: String): Boolean { return synchronized(orchestratorLock) { adOrchestrator?.isRewardedReady(placementId) ?: false } } /** * Check if a rewarded ad is loaded (alias for isReady) * * @param placementId The placement ID * @return true if ad is loaded and ready */ fun isLoaded(placementId: String): Boolean = isReady(placementId) /** * Destroy a specific rewarded ad * * @param placementId The placement ID to destroy */ fun destroy(placementId: String) { BCLogger.d(TAG, "Destroying rewarded ad: $placementId") synchronized(orchestratorLock) { adOrchestrator?.destroyRewardedAd(placementId) listeners.remove(placementId) } } /** * Destroy all cached rewarded ads */ fun destroyAll() { BCLogger.d(TAG, "Destroying all rewarded ads") synchronized(orchestratorLock) { adOrchestrator?.clearCache() listeners.clear() } } /** * Clear all cached rewarded ads */ fun clearCache() { destroyAll() } /** * Set a listener for a placement * * @param placementId The placement ID * @param listener The listener for events */ fun setListener(placementId: String, listener: RewardedAdListener?) { if (listener != null) { listeners[placementId] = listener } else { listeners.remove(placementId) } } private fun getOrCreateOrchestrator(context: Context?): AdOrchestrator { synchronized(orchestratorLock) { if (adOrchestrator == null) { val ctx = context?.applicationContext ?: throw IllegalStateException("Context required to create AdOrchestrator") val configManager = BigCrunchAds.getConfigManager() val analyticsClient = BigCrunchAds.getAnalyticsClient() val googleAdsAdapter = GoogleAdsAdapter(ctx, analyticsClient) val bidRequestClient = BigCrunchAds.bidRequestClient ?: com.bigcrunch.ads.core.BidRequestClient( httpClient = com.bigcrunch.ads.internal.HttpClient(), configManager = configManager, privacyStore = BigCrunchAds.privacyStore, s2sConfig = com.bigcrunch.ads.models.S2SConfig(enabled = false, serverUrl = "", timeoutMs = 0) ) adOrchestrator = AdOrchestrator( ctx, configManager, analyticsClient, bidRequestClient, googleAdsAdapter ) BCLogger.d(TAG, "Created new AdOrchestrator for rewarded ads") } return adOrchestrator!! } } }