using System;
using System.Collections;
using UnityEngine;

namespace Davanci.Nexus
{
    // Tiny delayed-callback runner for the ads layer. AppLovin MAX has no built-in retry, so after
    // a load failure the provider schedules a reload through here instead of hammering the network.
    // A single hidden DontDestroyOnLoad MonoBehaviour owns the coroutines.
    public sealed class NexusAdsRetry : MonoBehaviour
    {
        static NexusAdsRetry _instance;

        static NexusAdsRetry Instance
        {
            get
            {
                if (_instance != null) return _instance;
                var go = new GameObject("[Nexus] AdsRetry");
                _instance = go.AddComponent<NexusAdsRetry>();
                DontDestroyOnLoad(go);
                go.hideFlags = HideFlags.HideInHierarchy;
                return _instance;
            }
        }

        // Raised when the app returns to the foreground. The ads provider uses this to top up any
        // ad whose load was interrupted by a system overlay (most often the ATT prompt).
        public static event Action AppForegrounded;

        // Spawn the runner now so it receives Unity's focus callbacks even before any retry is
        // scheduled — otherwise the first foreground event after launch could be missed.
        public static void EnsureAlive()
        {
            if (Application.isPlaying) { var _ = Instance; }
        }

        public static void After(float seconds, Action action)
        {
            if (action == null) return;
            if (!Application.isPlaying) return;   // no coroutines outside play mode (e.g. self-test)
            Instance.StartCoroutine(Delay(seconds, action));
        }

        // Polls readiness on a slow cadence and raises NexusAds events when state changes.
        static bool _readinessWatchRunning;
        static bool _lastRewardedReady;
        static bool _lastInterstitialReady;

        public static void StartReadinessWatch()
        {
            if (_readinessWatchRunning || !Application.isPlaying) return;
            _readinessWatchRunning = true;
            _lastRewardedReady = NexusAds.IsRewardedReady;
            _lastInterstitialReady = NexusAds.IsInterstitialReady;
            Instance.StartCoroutine(WatchReadiness());
        }

        static IEnumerator WatchReadiness()
        {
            const float interval = 0.5f;
            while (true)
            {
                if (NexusAds.IsReady)
                {
                    bool rewarded = NexusAds.IsRewardedReady;
                    if (rewarded != _lastRewardedReady)
                    {
                        _lastRewardedReady = rewarded;
                        NexusAds.NotifyRewardedReadyChanged(rewarded);
                    }

                    bool interstitial = NexusAds.IsInterstitialReady;
                    if (interstitial != _lastInterstitialReady)
                    {
                        _lastInterstitialReady = interstitial;
                        NexusAds.NotifyInterstitialReadyChanged(interstitial);
                    }
                }

                yield return new WaitForSeconds(interval);
            }
        }

        void OnApplicationFocus(bool hasFocus)
        {
            if (hasFocus) AppForegrounded?.Invoke();
        }

        void OnApplicationPause(bool paused)
        {
            if (!paused) AppForegrounded?.Invoke();
        }

        static IEnumerator Delay(float seconds, Action action)
        {
            yield return new WaitForSeconds(seconds);
            try { action(); }
            catch (Exception e) { Debug.LogWarning($"[Nexus] Ads retry failed: {e.Message}"); }
        }
    }
}
