using System;
using Unity.Services.LevelPlay;

public class LevelPlayRewardedAdProvider : IRewardedAdProvider
{
    public string Name { get => "levelplay"; }

    public event EventHandler<double> OnAdLoaded;
    public event EventHandler<string> OnAdLoadFailed;
    public event EventHandler OnAdShown;
    public event EventHandler<string> OnAdShowFailed;
    public event EventHandler<bool> OnAdClosed;
    public event EventHandler<AdRevenueReceivedEventArgs> OnAdRevenueReceived;

    private string LevelPlayRewardedAdUnitId { get; }

    private LevelPlayRewardedAd RewardedAd { get; set; }

    public LevelPlayRewardedAdProvider(string adUnitId)
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Constructor] LevelPlayRewardedAdProvider()");

        LevelPlayRewardedAdUnitId = adUnitId;

        InstantiateRewardedAd();
    }

    public void LoadRewardedAd(double priceFloor = 0d)
    {
        AdHelper.Log($"[LevelPlayRewardedAdProvider] [Method] LoadRewardedAd(priceFloor: {priceFloor})");

        RewardedAd?.LoadAd();
    }

    public void NotifyLoss(string winnerDemandId, double ecpm)
    {
        AdHelper.Log($"[LevelPlayRewardedAdProvider] [Method] NotifyLoss(winner: {winnerDemandId}, ecpm: {ecpm})");

        InstantiateRewardedAd();
    }

    public void NotifyWin()
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] NotifyWin()");
    }

    public void ShowRewardedAd(string placementName)
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] ShowRewardedAd()");

        RewardedAd?.ShowAd(placementName);
    }

    private void InstantiateRewardedAd()
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] InstantiateRewardedAd()");

        if (RewardedAd != null)
        {
            UnsubscribeFromRewardedAdEvents(RewardedAd);
            RewardedAd.DestroyAd();
        }

        RewardedAd = new LevelPlayRewardedAd(LevelPlayRewardedAdUnitId);
        SubscribeToRewardedAdEvents(RewardedAd);
    }

    private void SubscribeToRewardedAdEvents(LevelPlayRewardedAd ad)
    {
        if (ad == null) return;

        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] SubscribeToRewardedAdEvents()");

        ad.OnAdLoaded += OnLevelPlayRewardedAdLoaded;
        ad.OnAdLoadFailed += OnLevelPlayRewardedAdLoadFailed;
        ad.OnAdDisplayed += OnLevelPlayRewardedAdDisplayed;
        ad.OnAdDisplayFailed += OnLevelPlayRewardedAdDisplayFailed;
        ad.OnAdClosed += OnLevelPlayRewardedAdClosed;
    }

    private void UnsubscribeFromRewardedAdEvents(LevelPlayRewardedAd ad)
    {
        if (ad == null) return;

        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] UnsubscribeFromRewardedAdEvents()");

        ad.OnAdLoaded -= OnLevelPlayRewardedAdLoaded;
        ad.OnAdLoadFailed -= OnLevelPlayRewardedAdLoadFailed;
        ad.OnAdDisplayed -= OnLevelPlayRewardedAdDisplayed;
        ad.OnAdDisplayFailed -= OnLevelPlayRewardedAdDisplayFailed;
        ad.OnAdClosed -= OnLevelPlayRewardedAdClosed;
    }

    private void OnLevelPlayRewardedAdLoaded(LevelPlayAdInfo adInfo)
    {
        double ecpm = AdHelper.GetRoundedEcpm((adInfo.Revenue ?? 0d) * 1000);
        AdHelper.Log($"[LevelPlayRewardedAdProvider] [Method] OnLevelPlayRewardedAdLoaded(ecpm: {ecpm}). Revenue is {adInfo.Revenue}");

        OnAdLoaded?.Invoke(this, ecpm);
    }

    private void OnLevelPlayRewardedAdLoadFailed(LevelPlayAdError error)
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] OnLevelPlayRewardedAdLoadFailed()");

        OnAdLoadFailed?.Invoke(this, error.ToString());
    }

    private void OnLevelPlayRewardedAdDisplayed(LevelPlayAdInfo adInfo)
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] OnLevelPlayRewardedAdDisplayed()");

        OnAdShown?.Invoke(this, EventArgs.Empty);

        var info = new AdInfo
        {
            AdType = "Rewarded",
            AdUnitId = adInfo.AdUnitId,
            CurrencyCode = "USD",
            MediationId = Name,
            NetworkAdUnitId = adInfo.InstanceId,
            NetworkName = adInfo.AdNetwork,
            Revenue = adInfo.Revenue ?? 0d,
            RevenuePrecision = adInfo.Precision,
        };

        OnAdRevenueReceived?.Invoke(this, new AdRevenueReceivedEventArgs(info));
    }

    private void OnLevelPlayRewardedAdDisplayFailed(LevelPlayAdDisplayInfoError error)
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] OnLevelPlayRewardedAdDisplayFailed()");

        InstantiateRewardedAd();
        OnAdShowFailed?.Invoke(this, error.ToString());
    }

    private void OnLevelPlayRewardedAdClosed(LevelPlayAdInfo adInfo)
    {
        AdHelper.Log("[LevelPlayRewardedAdProvider] [Method] OnLevelPlayRewardedAdClosed()");

        InstantiateRewardedAd();
        OnAdClosed?.Invoke(this, true);
    }
}
