using GoogleMobileAds.Api;
using GoogleMobileAds.Common;
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AdsManager : MonoBehaviour
{
    //test ad units
#if UNITY_ANDROID
    public string iAdUnit = "ca-app-pub-3940256099942544/1033173712";
#elif UNITY_IPHONE
    public string iAdUnit = "ca-app-pub-3940256099942544/4411468910";
#endif

    // test ad units
#if UNITY_ANDROID
    public string rAdUnit = "ca-app-pub-3940256099942544/5224354917";
#elif UNITY_IPHONE
      public string rAdUnit = "ca-app-pub-3940256099942544/1712485313";
#endif

    private InterstitialAd _interstitialAd;
    private int interstitialRetryAttempt = 1;
    private bool loadingiAd = false;
    private string iAdPlacement;

    private RewardedAd _rewardedAd;
    private int rewardedRetryAttempt = 1;
    private bool loadingrAd = false;
    private RewardedTypes rewardType;
    private bool isRewardAvailable = false;
    public bool isRewardedAdAvailable = false;
    public static AdsManager Instance;
    public Action<RewardedTypes> OnUserEarnedReward;
    public Action OnAdmobInitializedEvent;
    public Action<bool> OniAdLoading;
    public Action<bool> OnrAdLoading;
    public Action<bool> OniAdLoaded;
    public Action<bool> OnrAdLoaded;

    private void Awake()
    {
        if (Instance != null && Instance != this) 
        { 
            Destroy(this); 
        } 
        else 
        { 
            Instance = this; 
        }
        DontDestroyOnLoad(gameObject);
    }

    private void Start()
    {
        InitializeAdmob();
    }

    private void FixedUpdate()
    {
        if (isRewardAvailable)
        {
            isRewardAvailable = false;
            OnUserEarnedReward?.Invoke(rewardType);
        }
    }

    public void InitializeAdmob()
    {
        if (!CanShowAds()) return;

        MobileAds.RaiseAdEventsOnUnityMainThread = true;
        // Initialize the Google Mobile Ads SDK.
        MobileAds.Initialize(OnAdmobInitialized);
    }

    public void OnAdmobInitialized(InitializationStatus initStatus)
    {
        MobileAdsEventExecutor.ExecuteInUpdate(() =>
        {
            Debug.Log("Admob Initialized");
            OnAdmobInitializedEvent?.Invoke();
            Invoke(nameof(LoadInterstitialAdWithDelay), 3f);
            Invoke(nameof(LoadRewardedAdWithDelay), 6f);
        });
        
    }

    public bool CanShowAds()
    {
        return true;
    }

    private void OnAdPaid(AdValue adValue)
    {
        Debug.Log(String.Format("ad paid {0} {1}.",
            adValue.Value,
            adValue.CurrencyCode));
    }

    private void PauseGame()
    {
        Time.timeScale = 0f;
        AudioListener.pause = true;
    }

    private void ResumeGame()
    {
        Time.timeScale = 1f;
        AudioListener.pause = false;
    }

    #region Interstitial_Ads
    public void LoadInterstitialAdWithDelay()
    {
        if (!CanShowAds()) return;

        var currentAttempt = Mathf.Min(interstitialRetryAttempt, 5);
        var delayTime = Mathf.Pow(2, currentAttempt);
        if(!loadingiAd)
        {
            OniAdLoading?.Invoke(loadingiAd);
            loadingiAd = true;
            Invoke(nameof(LoadInterstitialAd), delayTime);
        }
    }

    private void LoadInterstitialAd()
    {
        // Clean up the old ad before loading a new one.
        if (_interstitialAd != null)
        {
            _interstitialAd.Destroy();
            _interstitialAd = null;
        }

        // create our request used to load the ad.
        var adRequest = new AdRequest();
        // send the request to load the ad.
        InterstitialAd.Load(iAdUnit, adRequest, OnInterstitialAdLoaded);
    }

    private void OnInterstitialAdLoaded(InterstitialAd ad, LoadAdError error)
    {
        MobileAdsEventExecutor.ExecuteInUpdate(() =>
        {
            loadingiAd = false;
            OniAdLoading?.Invoke(loadingiAd);
            // if error is not null, the load request failed.
            if (error != null || ad == null)
            {
                OniAdLoaded?.Invoke(false);
                interstitialRetryAttempt++;
                //load ad again
                LoadInterstitialAdWithDelay();
                Debug.LogError("interstitial ad failed to load an ad " +
                               "with error : " + error);
                return;
            }

            interstitialRetryAttempt = 1;
            Debug.Log("Interstitial ad loaded with response : "
                      + ad.GetResponseInfo());
            OniAdLoaded?.Invoke(true);
            _interstitialAd = ad;
            RegisterEventHandlers(_interstitialAd);
        });
    }

    public void ShowInterstitialAd(string adPlacement)
    {
        if (!CanShowAds()) return;

        iAdPlacement = adPlacement;
        if (_interstitialAd != null && _interstitialAd.CanShowAd())
        {
            Debug.Log("Showing interstitial ad.");
            _interstitialAd.Show();
        }
        else
        {
            Debug.LogError("Interstitial ad is not ready yet.");
            LoadInterstitialAdWithDelay();
        }
    }

    private void RegisterEventHandlers(InterstitialAd interstitialAd)
    {
        // Raised when the ad is estimated to have earned money.
        //interstitialAd.OnAdPaid += OnAdPaid;
        // Raised when an impression is recorded for an ad.
        //interstitialAd.OnAdImpressionRecorded += () =>
        //{
        //    Debug.Log("Interstitial ad recorded an impression.");
        //};
        // Raised when a click is recorded for an ad.
        //interstitialAd.OnAdClicked += () =>
        //{
        //    Debug.Log("Interstitial ad was clicked.");
        //};
        //Raised when an ad opened full screen content.
        interstitialAd.OnAdFullScreenContentOpened += OnInterstitialAdOpen;
        // Raised when the ad closed full screen content.
        interstitialAd.OnAdFullScreenContentClosed += () =>
        {
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                Debug.Log("Interstitial ad full screen content closed.");
                ResumeGame();
                LoadInterstitialAdWithDelay();
            });
        };
        // Raised when the ad failed to open full screen content.
        interstitialAd.OnAdFullScreenContentFailed += (AdError error) =>
        {
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                Debug.LogError("Interstitial ad failed to open full screen content " +
                               "with error : " + error);
                LoadInterstitialAdWithDelay();
            });
        };
    }

    private void OnInterstitialAdOpen()
    {
        MobileAdsEventExecutor.ExecuteInUpdate(() =>
        {
            PauseGame();
        });
    }
    #endregion

    #region Rewarded_Ads

    public void LoadRewardedAdWithDelay()
    {
        if (!CanShowAds()) return;

        var currentAttempt = Mathf.Min(rewardedRetryAttempt, 5);
        var delayTime = Mathf.Pow(2, currentAttempt);
        if (!loadingrAd)
        {
            OnrAdLoading?.Invoke(loadingrAd);
            loadingrAd = true;
            Invoke(nameof(LoadRewardedAd), delayTime);
        }
    }

    public void LoadRewardedAd()
    {
        // Clean up the old ad before loading a new one.
        if (_rewardedAd != null)
        {
            _rewardedAd.Destroy();
            _rewardedAd = null;
        }

        Debug.Log("Loading the rewarded ad.");

        // create our request used to load the ad.
        var adRequest = new AdRequest();

        // send the request to load the ad.
        RewardedAd.Load(rAdUnit, adRequest, OnRewardedAdLoaded);
    }

    private void OnRewardedAdLoaded(RewardedAd ad, LoadAdError error)
    {
        MobileAdsEventExecutor.ExecuteInUpdate(() =>
        {
            loadingrAd = false;
            OnrAdLoading?.Invoke(loadingrAd);
            // if error is not null, the load request failed.
            if (error != null || ad == null)
            {
                OnrAdLoaded?.Invoke(false);
                isRewardedAdAvailable = false;
                rewardedRetryAttempt++;
                //load ad again
                LoadRewardedAdWithDelay();
                Debug.LogError("rewarded ad failed to load an ad " +
                               "with error : " + error);
                return;
            }

            rewardedRetryAttempt = 1;
            Debug.Log("rewarded ad loaded with response : "
                      + ad.GetResponseInfo());

            isRewardedAdAvailable = true;
            OnrAdLoaded?.Invoke(true);
            _rewardedAd = ad;
            RegisterEventHandlers(_rewardedAd);
        });
    }

    private void RegisterEventHandlers(RewardedAd ad)
    {
        // Raised when the ad is estimated to have earned money.
        //ad.OnAdPaid += OnAdPaid;
        // Raised when an impression is recorded for an ad.
        //ad.OnAdImpressionRecorded += () =>
        //{
        //    Debug.Log("Rewarded ad recorded an impression.");
        //};
        // Raised when a click is recorded for an ad.
        //ad.OnAdClicked += () =>
        //{
        //    Debug.Log("Rewarded ad was clicked.");
        //};
        // Raised when an ad opened full screen content.
        ad.OnAdFullScreenContentOpened += OnRewardedAdOpen;
        // Raised when the ad closed full screen content.
        ad.OnAdFullScreenContentClosed += () =>
        {
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                Debug.Log("Rewarded ad full screen content closed.");
                ResumeGame();
                LoadRewardedAdWithDelay();
            });
        };
        // Raised when the ad failed to open full screen content.
        ad.OnAdFullScreenContentFailed += (AdError error) =>
        {
            MobileAdsEventExecutor.ExecuteInUpdate(() =>
            {
                Debug.LogError("Rewarded ad failed to open full screen content " +
                               "with error : " + error);
                LoadRewardedAdWithDelay();
            });
        };
    }

    private void OnRewardedAdOpen()
    {
        MobileAdsEventExecutor.ExecuteInUpdate(() =>
        {
            PauseGame();
        });
    }

    public void ShowRewardedAd(RewardedTypes rewardFor)
    {
        rewardType = rewardFor;

        if (!CanShowAds())
        {
            isRewardAvailable = true;
            return;
        }

        if (_rewardedAd != null && _rewardedAd.CanShowAd())
        {
            _rewardedAd.Show((Reward reward) =>
            {
                // TODO: Reward the user.
                isRewardAvailable = true;
            });
        }
        else
        {
            Debug.LogError("No Video!");
            LoadRewardedAdWithDelay();
        }
    }
    #endregion


}

public enum RewardedTypes
{
    None,
    Revive,
    ClaimDouble,
    LevelUnlock,
    FootSteps,
    NewCharacter,
    Color,
    Animation,
    InventoryPurchase,
    Hint,
    Coins
}