#if DAVANCI_LEVELPLAY
using System;
using Unity.Services.LevelPlay;
using UnityEngine;

namespace Davanci.Nexus
{
    // Mediation slot backed by Unity LevelPlay (ironSource). Wraps LevelPlay's per-ad-unit objects
    // (LevelPlayRewardedAd / LevelPlayInterstitialAd / LevelPlayBannerAd) behind the same
    // INexusAdsProvider contract as the AppLovin MAX provider. Compiled only when LevelPlay
    // is imported (DAVANCI_LEVELPLAY). Requires LevelPlay SDK with per-ad OnAdImpressionDataReady.
    public sealed class NexusLevelPlayProvider : INexusAdsProvider
    {
        string _rewardedId, _interstitialId, _bannerId;
        LevelPlayRewardedAd _rewarded;
        LevelPlayInterstitialAd _interstitial;
        LevelPlayBannerAd _banner;

        Action<NexusAdResult> _rewardedCb;
        string _rewardedPlacement;
        bool _rewardEarned;
        bool _rewardResolved;
        bool _rewardedLoading;

        Action<NexusAdResult> _interstitialCb;
        string _interstitialPlacement;
        bool _interstitialLoading;

        Action<bool> _onReady;
        bool _testSuiteMode;
        bool? _attTrackingAuthorized;
        int _rewardedLoadAttempts;
        int _interstitialLoadAttempts;

        const float FirstLoadDelaySeconds = 2f;
        static readonly float[] LoadRetryDelays = { 5f, 15f, 30f };

        public bool IsInitialized { get; private set; }

        public void Initialize(NexusAdsSettings settings, Action<bool> onReady)
        {
            _rewardedId = settings.RewardedAdUnitId;
            _interstitialId = settings.InterstitialAdUnitId;
            _bannerId = settings.BannerAdUnitId;
            _onReady = onReady;
            _attTrackingAuthorized = settings.AttTrackingAuthorized;

            LevelPlay.OnInitSuccess += OnInitSuccess;
            LevelPlay.OnInitFailed += OnInitFailed;

            NexusAdsRetry.EnsureAlive();
            NexusAdsRetry.AppForegrounded -= OnAppForegrounded;
            NexusAdsRetry.AppForegrounded += OnAppForegrounded;

            _testSuiteMode = settings.TestSuiteMode;
            if (_testSuiteMode)
                LevelPlay.SetMetaData("is_test_suite", "enable");

            NexusLevelPlayPrivacy.ApplyBeforeInit(_attTrackingAuthorized);

            LevelPlay.Init(settings.AppKey);
        }

        void OnInitSuccess(LevelPlayConfiguration config)
        {
            IsInitialized = true;

            if (!_testSuiteMode)
            {
                SetupRewarded();
                SetupInterstitial();
            }
            var cb = _onReady; _onReady = null;
            cb?.Invoke(true);

            if (!_testSuiteMode)
                NexusAdsRetry.After(FirstLoadDelaySeconds, ScheduleInitialLoads);
        }

        void OnInitFailed(LevelPlayInitError error)
        {
            Debug.LogWarning("[Nexus] LevelPlay init failed: " + error?.ErrorMessage);
            var cb = _onReady; _onReady = null;
            cb?.Invoke(false);
        }

        // ---- rewarded ------------------------------------------------------------------

        void SetupRewarded()
        {
            if (string.IsNullOrEmpty(_rewardedId)) return;
            _rewarded = new LevelPlayRewardedAd(_rewardedId);
            _rewarded.OnAdLoaded += _ =>
            {
                _rewardedLoading = false;
                _rewardedLoadAttempts = 0;
            };
            _rewarded.OnAdLoadFailed += error =>
            {
                _rewardedLoading = false;
                Debug.LogWarning("[Nexus] LevelPlay rewarded load failed: " + error?.ErrorMessage);
                ScheduleRewardedRetry();
            };
            _rewarded.OnAdRewarded += (info, reward) => _rewardEarned = true;
            _rewarded.OnAdImpressionDataReady += data => EmitImpression(data, "rewarded", _rewardedPlacement);
            _rewarded.OnAdDisplayFailed += (info, error) =>
            {
                ResolveRewarded(NexusAdStatus.Failed, error?.ErrorMessage);
                LoadRewarded();
            };
            _rewarded.OnAdClosed += _ =>
            {
                ResolveRewarded(_rewardEarned ? NexusAdStatus.Rewarded : NexusAdStatus.Dismissed);
                LoadRewarded();
            };
        }

        void ScheduleInitialLoads()
        {
            LoadRewarded();
            LoadInterstitial();
        }

        void ScheduleRewardedRetry()
        {
            int idx = Mathf.Min(_rewardedLoadAttempts, LoadRetryDelays.Length - 1);
            _rewardedLoadAttempts++;
            NexusAdsRetry.After(LoadRetryDelays[idx], LoadRewarded);
        }

        void LoadRewarded()
        {
            if (_rewarded == null || _rewardedLoading || _rewarded.IsAdReady()) return;
            _rewardedLoading = true;
            _rewarded.LoadAd();
        }

        void OnAppForegrounded()
        {
            if (!IsInitialized) return;
            NexusAdsRetry.After(FirstLoadDelaySeconds, ScheduleInitialLoads);
        }

        public bool IsRewardedReady => IsInitialized && _rewarded != null && _rewarded.IsAdReady();

        public void ShowRewarded(string placement, Action<NexusAdResult> onResult)
        {
            if (!IsInitialized) { onResult?.Invoke(NexusAdResult.Make(NexusAdStatus.NotInitialized, placement)); return; }
            if (!IsRewardedReady)
            {
                LoadRewarded();
                onResult?.Invoke(NexusAdResult.Make(NexusAdStatus.NotReady, placement));
                return;
            }
            _rewardedCb = onResult;
            _rewardedPlacement = placement;
            _rewardEarned = false;
            _rewardResolved = false;
            _rewarded.ShowAd();
        }

        // ---- interstitial --------------------------------------------------------------

        void SetupInterstitial()
        {
            if (string.IsNullOrEmpty(_interstitialId)) return;
            _interstitial = new LevelPlayInterstitialAd(_interstitialId);
            _interstitial.OnAdLoaded += _ =>
            {
                _interstitialLoading = false;
                _interstitialLoadAttempts = 0;
            };
            _interstitial.OnAdLoadFailed += error =>
            {
                _interstitialLoading = false;
                Debug.LogWarning("[Nexus] LevelPlay interstitial load failed: " + error?.ErrorMessage);
                ScheduleInterstitialRetry();
            };
            _interstitial.OnAdImpressionDataReady += data => EmitImpression(data, "interstitial", _interstitialPlacement);
            _interstitial.OnAdDisplayFailed += (info, error) =>
            {
                ResolveInterstitial(NexusAdStatus.Failed, error?.ErrorMessage);
                LoadInterstitial();
            };
            _interstitial.OnAdClosed += _ =>
            {
                ResolveInterstitial(NexusAdStatus.Shown);
                LoadInterstitial();
            };
        }

        void ScheduleInterstitialRetry()
        {
            int idx = Mathf.Min(_interstitialLoadAttempts, LoadRetryDelays.Length - 1);
            _interstitialLoadAttempts++;
            NexusAdsRetry.After(LoadRetryDelays[idx], LoadInterstitial);
        }

        void LoadInterstitial()
        {
            if (_interstitial == null || _interstitialLoading || _interstitial.IsAdReady()) return;
            _interstitialLoading = true;
            _interstitial.LoadAd();
        }

        public bool IsInterstitialReady => IsInitialized && _interstitial != null && _interstitial.IsAdReady();

        public void ShowInterstitial(string placement, Action<NexusAdResult> onResult)
        {
            if (!IsInitialized) { onResult?.Invoke(NexusAdResult.Make(NexusAdStatus.NotInitialized, placement)); return; }
            if (!IsInterstitialReady)
            {
                LoadInterstitial();
                onResult?.Invoke(NexusAdResult.Make(NexusAdStatus.NotReady, placement));
                return;
            }
            _interstitialCb = onResult;
            _interstitialPlacement = placement;
            _interstitial.ShowAd();
        }

        // ---- banner / MREC -------------------------------------------------------------

        public void ShowBanner(string placement)
        {
            if (!IsInitialized || string.IsNullOrEmpty(_bannerId)) return;
            if (_banner == null)
            {
                _banner = new LevelPlayBannerAd(_bannerId);
                _banner.OnAdImpressionDataReady += data => EmitImpression(data, "banner", null);
                _banner.LoadAd();
            }
            _banner.ShowAd();
        }

        public void HideBanner() => _banner?.HideAd();

        public void LaunchTestSuite() => LevelPlay.LaunchTestSuite();

        // Impression callbacks may arrive off the main thread — hop before analytics.
        void EmitImpression(LevelPlayImpressionData data, string formatFallback, string placement)
        {
            if (data?.Revenue == null) return;
            string format = string.IsNullOrEmpty(data.AdFormat) ? formatFallback : data.AdFormat;
            double revenue = data.Revenue.Value;
            string network = data.AdNetwork;
            string adUnit = data.MediationAdUnitName;
            NexusAdsRetry.After(0f, () =>
                DavanciNexus.AdRevenue("LevelPlay", network, format, revenue, adUnit, "USD", placement));
        }

        void ResolveRewarded(NexusAdStatus status, string message = "")
        {
            if (_rewardResolved || _rewardedCb == null) return;
            _rewardResolved = true;
            var cb = _rewardedCb;
            _rewardedCb = null;
            _rewardEarned = false;
            cb?.Invoke(NexusAdResult.Make(status, _rewardedPlacement, message));
        }

        void ResolveInterstitial(NexusAdStatus status, string message = "")
        {
            var cb = _interstitialCb; _interstitialCb = null;
            cb?.Invoke(NexusAdResult.Make(status, _interstitialPlacement, message));
        }
    }
}
#endif
