using System;
using Bidon.Mediation;

public class BidonBannerAdProvider : IBannerAdProvider
{
    public string Name { get => "bidon"; }

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

    private string AuctionKey { get; }

    private BidonBannerAd _bidonBannerAd;
    private BidonBannerAd _bidonBannerAdOld;

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

        AuctionKey = auctionKey;

        InstantiateBannerAd();
    }

    public void InstantiateBannerAd()
    {
        AdHelper.Log("[BidonBannerAdProvider] [Method] InstantiateBannerAd()");

        if (_bidonBannerAd != null)
        {
            UnsubscribeFromBannerAdEvents(_bidonBannerAdOld);
            _bidonBannerAdOld?.Dispose();
            _bidonBannerAdOld = _bidonBannerAd;
        }

        _bidonBannerAd = new BidonBannerAd(AuctionKey);
        _bidonBannerAd?.SetFormat(BidonBannerFormat.Banner);
        _bidonBannerAd?.SetPredefinedPosition(BidonBannerPosition.HorizontalBottom);
        SubscribeToBannerAdEvents(_bidonBannerAd);
    }

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

        _bidonBannerAd?.Load(priceFloor);
    }

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

        _bidonBannerAd?.NotifyLoss(winnerDemandId, ecpm);
    }

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

        _bidonBannerAd?.NotifyWin();
    }

    public void ShowBannerAd()
    {
        AdHelper.Log("[BidonBannerAdProvider] [Method] ShowBannerAd()");

        _bidonBannerAd?.SetExtraData("placement", "bidon");
        _bidonBannerAd?.Show();
    }

    public void HideBannerAd()
    {
        AdHelper.Log("[BidonBannerAdProvider] [Method] HideBannerAd()");

        _bidonBannerAd?.Hide();
    }

    private void SubscribeToBannerAdEvents(BidonBannerAd ad)
    {
        if (ad == null) return;

        AdHelper.Log("[BidonBannerAdProvider] [Method] SubscribeToBannerAdEvents()");

        ad.OnAdLoaded += OnBidonBannerAdLoaded;
        ad.OnAdLoadFailed += OnBidonBannerAdLoadFailed;
        ad.OnAdShown += OnBidonBannerAdShown;
        ad.OnAdRevenueReceived += OnBidonBannerAdRevenueReceived;
    }

    private void UnsubscribeFromBannerAdEvents(BidonBannerAd ad)
    {
        if (ad == null) return;

        AdHelper.Log("[BidonBannerAdProvider] [Method] UnsubscribeFromBannerAdEvents()");

        ad.OnAdLoaded -= OnBidonBannerAdLoaded;
        ad.OnAdLoadFailed -= OnBidonBannerAdLoadFailed;
        ad.OnAdShown -= OnBidonBannerAdShown;
        ad.OnAdRevenueReceived -= OnBidonBannerAdRevenueReceived;
    }

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

        OnAdLoaded?.Invoke(this, price);
    }

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

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

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

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

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