using System;
using System.Collections;
using ShiroginSDK.Runtime.Core.SDK;
using ShiroginSDK.Runtime.Core.Utils;
using ShiroginSDK.Runtime.Modules.Data.Scripts;
using ShiroginSDK.Runtime.Modules.Data.Scripts.Enums;
using ShiroginSDK.Runtime.Modules.Events;
using ShiroginSDK.Runtime.Services.Base;
using ShiroginSDK.Runtime.Services.Interfaces;
using UnityEngine;
namespace ShiroginSDK.Runtime.Services.Implementations.Ads
{
///
/// Handles Rewarded, Interstitial and Banner ads using AppLovin MAX SDK.
///
public class AdsService : ServiceBase, IAdsService
{
private ShiroginConfig _config;
private int _retryAttempt;
private bool _canShowInterstitial;
private int _addShowInterstitialTime;
private Action _shouldReward;
private Coroutine _interstitialCycle;
private IDataService _dataService;
private IEventService _eventService;
// ----------------------------------------------------
// Initialization
// ----------------------------------------------------
protected override void OnInitialize()
{
// Resolve dependencies
_dataService = ServiceLocator.Get();
_eventService = ServiceLocator.Get();
_config = ShiroginConfig.Load();
if (string.IsNullOrEmpty(_config.applovinSdkKey))
{
Debug.LogError("[ShiroginSDK] Missing AppLovin SDK key in SDKConfig.");
return;
}
MaxSdk.SetSdkKey(_config.applovinSdkKey);
MaxSdk.InitializeSdk();
InitializeRewardedAds();
var storeData = _dataService.Get();
if (!storeData.HasRemovedAds)
{
InitializeInterstitialAds();
InitializeBannerAds();
}
if (Application.internetReachability != NetworkReachability.NotReachable)
_interstitialCycle = CoroutineRunner.Start(InterstitialCycle());
}
protected override void OnDispose()
{
if (_interstitialCycle != null)
CoroutineRunner.Stop(_interstitialCycle);
}
// ----------------------------------------------------
// Rewarded Ads
// ----------------------------------------------------
public bool IsRewardedReady => MaxSdk.IsRewardedAdReady(GetRewardedId());
public void ShowRewarded(Action onComplete)
{
_shouldReward = onComplete;
var economy = _dataService.Get();
if (economy.RewardedTicket > 0)
{
economy.SpendCurrency(CurrencyType.RewardedTicket, 1);
_shouldReward?.Invoke(true);
return;
}
if (Application.internetReachability == NetworkReachability.NotReachable)
{
_eventService.Invoke(new ShiroginEvents.Connection.NoConnectionEvent());
_shouldReward?.Invoke(false);
return;
}
// 🔹 Tam buraya ekle (önce reklam hazır mı kontrol et)
if (!MaxSdk.IsRewardedAdReady(GetRewardedId()))
{
Debug.LogWarning("[AdsService] ⚠️ Rewarded ad not ready — NoAdsAvailable event triggered.");
_eventService.Invoke(new ShiroginEvents.Ads.RewardedAdUnavailableEvent()); // Popup
_shouldReward?.Invoke(false);
return;
}
// 🔹 Eğer buraya geldiyse reklam hazır, güvenle göster
MaxSdk.ShowRewardedAd(GetRewardedId());
}
private void InitializeRewardedAds()
{
// Reset retry counter
_retryAttempt = 0;
// --- When ad is successfully loaded
MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += (adUnitId, info) =>
{
_retryAttempt = 0;
Debug.Log($"[AdsService] ✅ Rewarded loaded: {adUnitId}");
};
// --- When ad fails to load
MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += (adUnitId, error) =>
{
_retryAttempt++;
var retryDelay = Math.Pow(2, Math.Min(6, _retryAttempt));
Debug.LogWarning($"[AdsService] ⚠️ Rewarded load failed. Retrying in {retryDelay:0.0}s...");
CoroutineRunner.InvokeDelayed(LoadRewardedAd, (float)retryDelay);
};
// --- When ad is displayed
MaxSdkCallbacks.Rewarded.OnAdDisplayedEvent += (adUnitId, info) =>
{
Debug.Log($"[AdsService] ▶️ Rewarded ad displayed: {adUnitId}");
};
// --- When ad fails to display
MaxSdkCallbacks.Rewarded.OnAdDisplayFailedEvent += (adUnitId, error, info) =>
{
Debug.LogError($"[AdsService] ❌ Rewarded display failed: {error.Message}");
LoadRewardedAd(); // Retry load immediately
};
// --- When ad is hidden (after being watched or skipped)
MaxSdkCallbacks.Rewarded.OnAdHiddenEvent += (adUnitId, info) =>
{
Debug.Log("[AdsService] 🧹 Rewarded closed. Reloading...");
LoadRewardedAd(); // Always reload when ad is closed
};
// --- When user earns reward
MaxSdkCallbacks.Rewarded.OnAdReceivedRewardEvent += OnRewardedCompleted;
// Initial load
LoadRewardedAd();
}
private void OnRewardedCompleted(string id, MaxSdkBase.Reward reward, MaxSdkBase.AdInfo info)
{
_shouldReward?.Invoke(true);
_eventService.Invoke(new ShiroginEvents.Ads.AdAnalyticsEvent(info.NetworkName, id, info.AdFormat + "_Reward",
true, info.Revenue));
_addShowInterstitialTime += 50;
// ✅ Yeni reklam yükle (önemli!)
LoadRewardedAd();
}
private void LoadRewardedAd()
{
MaxSdk.LoadRewardedAd(GetRewardedId());
}
// ----------------------------------------------------
// Interstitial Ads
// ----------------------------------------------------
private IEnumerator InterstitialCycle()
{
while (true)
{
yield return new WaitForSeconds(180f + _addShowInterstitialTime);
_canShowInterstitial = true;
_addShowInterstitialTime = 0;
yield return new WaitUntil(() => !_canShowInterstitial);
}
}
private void InitializeInterstitialAds()
{
MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += (_, _) => _retryAttempt = 0;
MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += (_, _) =>
{
_retryAttempt++;
var delay = Math.Pow(2, Math.Min(6, _retryAttempt));
CoroutineRunner.InvokeDelayed(LoadInterstitial, (float)delay);
};
LoadInterstitial();
}
private void LoadInterstitial()
{
MaxSdk.LoadInterstitial(GetInterstitialId());
}
public void ShowInterstitial(bool forceShow = false)
{
var storeData = _dataService.Get();
if (storeData.HasRemovedAds)
return;
if ((forceShow || _canShowInterstitial) && MaxSdk.IsInterstitialReady(GetInterstitialId()))
{
MaxSdk.ShowInterstitial(GetInterstitialId());
LoadInterstitial();
_canShowInterstitial = false;
}
}
// ----------------------------------------------------
// Banner Ads
// ----------------------------------------------------
private void InitializeBannerAds()
{
MaxSdk.CreateBanner(GetBannerId(), MaxSdkBase.BannerPosition.BottomCenter);
MaxSdkCallbacks.Banner.OnAdLoadedEvent += (_, _) => { };
MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += (_, _) => { };
}
public void CreateBanner(bool show)
{
DestroyBanner();
MaxSdk.CreateBanner(GetBannerId(), MaxSdkBase.BannerPosition.BottomCenter);
if (show) MaxSdk.ShowBanner(GetBannerId());
}
public void ShowBanner()
{
MaxSdk.ShowBanner(GetBannerId());
}
public void HideBanner()
{
MaxSdk.HideBanner(GetBannerId());
}
public void DestroyBanner()
{
MaxSdk.DestroyBanner(GetBannerId());
}
// ----------------------------------------------------
// Helpers
// ----------------------------------------------------
#if UNITY_IOS
private string GetRewardedId() => _config.rewardedAdUnitIdIos;
private string GetInterstitialId() => _config.interstitialAdUnitIdIos;
private string GetBannerId() => _config.bannerAdUnitIdIos;
#else
private string GetRewardedId()
{
return _config.rewardedAdUnitIdDrd;
}
private string GetInterstitialId()
{
return _config.interstitialAdUnitIdDrd;
}
private string GetBannerId()
{
return _config.bannerAdUnitIdDrd;
}
#endif
}
}