using System;
using Bidon.Mediation;

public class BidonInterstitialAdProvider : IInterstitialAdProvider
{
    public string Name { get => "bidon"; }

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

    private string AuctionKey { get; }

    private BidonInterstitialAd _bidonInterstitialAd;
    private BidonInterstitialAd _bidonInterstitialAdOld;

    public BidonInterstitialAdProvider(string auctionKey)
    {
        AdHelper.Log("[BidonInterstitialAdProvider] [Constructor] BidonInterstitialAdProvider()");

        AuctionKey = auctionKey;

        InstantiateInterstitialAd();
    }

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

        _bidonInterstitialAd?.Load(priceFloor);
    }

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

        _bidonInterstitialAd?.NotifyLoss(winnerDemandId, ecpm);
        InstantiateInterstitialAd();
    }

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

        _bidonInterstitialAd?.NotifyWin();
    }

    public void ShowInterstitialAd(string placementName)
    {
        AdHelper.Log("[BidonInterstitialAdProvider] [Method] ShowInterstitialAd()");

        _bidonInterstitialAd?.SetExtraData("placement", placementName);
        _bidonInterstitialAd?.Show();
    }

    private void InstantiateInterstitialAd()
    {
        AdHelper.Log("[BidonInterstitialAdProvider] [Method] InstantiateInterstitialAd()");

        if (_bidonInterstitialAd != null)
        {
            UnsubscribeFromInterstitialAdEvents(_bidonInterstitialAdOld);
            _bidonInterstitialAdOld?.Dispose();
            _bidonInterstitialAdOld = _bidonInterstitialAd;
        }

        _bidonInterstitialAd = new BidonInterstitialAd(AuctionKey);
        SubscribeToInterstitialAdEvents(_bidonInterstitialAd);
    }

    private void SubscribeToInterstitialAdEvents(BidonInterstitialAd ad)
    {
        if (ad == null) return;

        AdHelper.Log("[BidonInterstitialAdProvider] [Method] SubscribeToInterstitialAdEvents()");

        ad.OnAdLoaded += OnBidonInterstitialAdLoaded;
        ad.OnAdLoadFailed += OnBidonInterstitialAdLoadFailed;
        ad.OnAdShown += OnBidonInterstitialAdShown;
        ad.OnAdShowFailed += OnBidonInterstitialAdShowFailed;
        ad.OnAdClosed += OnBidonInterstitialAdClosed;
        ad.OnAdRevenueReceived += OnBidonInterstitialAdRevenueReceived;
    }

    private void UnsubscribeFromInterstitialAdEvents(BidonInterstitialAd ad)
    {
        if (ad == null) return;

        AdHelper.Log("[BidonInterstitialAdProvider] [Method] UnsubscribeFromInterstitialAdEvents()");

        ad.OnAdLoaded -= OnBidonInterstitialAdLoaded;
        ad.OnAdLoadFailed -= OnBidonInterstitialAdLoadFailed;
        ad.OnAdShown -= OnBidonInterstitialAdShown;
        ad.OnAdShowFailed -= OnBidonInterstitialAdShowFailed;
        ad.OnAdClosed -= OnBidonInterstitialAdClosed;
        ad.OnAdRevenueReceived -= OnBidonInterstitialAdRevenueReceived;
    }

    private void OnBidonInterstitialAdLoaded(object sender, BidonAdLoadedEventArgs args)
    {
        double price = AdHelper.GetRoundedEcpm(args.Ad.Price);
        AdHelper.Log($"[BidonInterstitialAdProvider] [Callback] OnAdLoaded(ecpm: {price})");

        OnAdLoaded?.Invoke(this, price);
    }

    private void OnBidonInterstitialAdLoadFailed(object sender, BidonAdLoadFailedEventArgs args)
    {
        AdHelper.Log($"[BidonInterstitialAdProvider] [Callback] OnAdLoadFailed(cause: {args.Cause})");

        OnAdLoadFailed?.Invoke(this, args.Cause.ToString());
    }

    private void OnBidonInterstitialAdShown(object sender, BidonAdShownEventArgs args)
    {
        AdHelper.Log("[BidonInterstitialAdProvider] [Callback] OnAdShown()");

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

    private void OnBidonInterstitialAdShowFailed(object sender, BidonAdShowFailedEventArgs args)
    {
        AdHelper.Log($"[BidonInterstitialAdProvider] [Callback] OnAdShowFailed(cause: {args.Cause})");

        InstantiateInterstitialAd();
        OnAdShowFailed?.Invoke(this, args.Cause.ToString());
    }

    private void OnBidonInterstitialAdClosed(object sender, BidonAdClosedEventArgs args)
    {
        AdHelper.Log("[BidonInterstitialAdProvider] [Callback] OnAdClosed()");

        InstantiateInterstitialAd();
        OnAdClosed?.Invoke(this, EventArgs.Empty);
    }

    private void OnBidonInterstitialAdRevenueReceived(object sender, BidonAdRevenueReceivedEventArgs args)
    {
        AdHelper.Log("[BidonInterstitialAdProvider] [Callback] OnAdRevenueReceived()");

        var info = new AdInfo
        {
            AdType = args.Ad.AdType.ToString(),
            AdUnitId = AuctionKey,
            CurrencyCode = args.AdValue.CurrencyCode,
            MediationId = Name,
            NetworkAdUnitId = args.Ad.AdUnit.Uid,
            NetworkName = args.Ad.NetworkName,
            Revenue = args.AdValue.AdRevenue,
            RevenuePrecision = args.AdValue.RevenuePrecision.ToString(),
        };
        OnAdRevenueReceived?.Invoke(this, new AdRevenueReceivedEventArgs(info));
    }
}
