using System;
using Bidon.Mediation;

public class BidonRewardedAdProvider : IRewardedAdProvider
{
    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<bool> OnAdClosed;
    public event EventHandler<AdRevenueReceivedEventArgs> OnAdRevenueReceived;

    private string AuctionKey { get; }

    private BidonRewardedAd _bidonRewardedAd;
    private BidonRewardedAd _bidonRewardedAdOld;

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

        AuctionKey = auctionKey;

        InstantiateRewardedAd();
    }

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

        _bidonRewardedAd?.Load(priceFloor);
    }

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

        _bidonRewardedAd?.NotifyLoss(winnerDemandId, ecpm);
        InstantiateRewardedAd();
    }

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

        _bidonRewardedAd?.NotifyWin();
    }

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

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

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

        if (_bidonRewardedAd != null)
        {
            UnsubscribeFromRewardedAdEvents(_bidonRewardedAdOld);
            _bidonRewardedAdOld?.Dispose();
            _bidonRewardedAdOld = _bidonRewardedAd;
        }

        _bidonRewardedAd = new BidonRewardedAd(AuctionKey);
        SubscribeToRewardedAdEvents(_bidonRewardedAd);
    }

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

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

        ad.OnAdLoaded += OnBidonRewardedAdLoaded;
        ad.OnAdLoadFailed += OnBidonRewardedAdLoadFailed;
        ad.OnAdShown += OnBidonRewardedAdShown;
        ad.OnAdShowFailed += OnBidonRewardedAdShowFailed;
        ad.OnAdClosed += OnBidonRewardedAdClosed;
        ad.OnAdRevenueReceived += OnBidonRewardedAdRevenueReceived;
    }

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

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

        ad.OnAdLoaded -= OnBidonRewardedAdLoaded;
        ad.OnAdLoadFailed -= OnBidonRewardedAdLoadFailed;
        ad.OnAdShown -= OnBidonRewardedAdShown;
        ad.OnAdShowFailed -= OnBidonRewardedAdShowFailed;
        ad.OnAdClosed -= OnBidonRewardedAdClosed;
        ad.OnAdRevenueReceived -= OnBidonRewardedAdRevenueReceived;
    }

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

        OnAdLoaded?.Invoke(this, price);
    }

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

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

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

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

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

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

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

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

    private void OnBidonRewardedAdRevenueReceived(object sender, BidonAdRevenueReceivedEventArgs args)
    {
        AdHelper.Log("[BidonRewardedAdProvider] [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));
    }
}
