using Adplay.Behaviours.Actions;
using Adplay.DataContainer;
using Adplay.Model;
using Adplay.Request;
using Adplay.Utility;
using Adplay.View;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using UnityEngine;

namespace Adplay.Behaviours
{
    public class AdPlayManager : MonoBehaviour
    {
        [SerializeField] private AdPlayBatchSender adPlayBatchSender;
        [SerializeField] private AdPlayPopUpButton popUpButton;
        [SerializeField] private AdPlayBanner banner;
        [SerializeField] private AdPlaySplash splash;
        [SerializeField] private AdPlayPopUp popUp;
        [SerializeField] private AdPlayInterstitialSound interstitialSound;

        [Header("Scriptable objects")]
        [SerializeField] private AdPlayRequest request;
        [SerializeField] private ActiveAds activeAds;
        [SerializeField] private EngagementData engagementData;

        private static AdPlayManager instance;
        private static bool isInitialized;
        private static int currentTryCount = 0;
        private static InitializeState initializeState = InitializeState.NotInitialized;
        public static event Action OnGetAdsComplete;
        public static AdPlayManager Instance
        {
            get
            {
                if (instance == null)
                    instance = FindAnyObjectByType<AdPlayManager>();
                return instance;
            }
        }

        private async void Awake()
        {
            if (Instance != this)
            {
                Destroy(gameObject);
                return;
            }
            DontDestroyOnLoad(gameObject);
            await Initialize();
        }

        public static async Task Initialize()
        {
            if (Instance == null)
            {
                Debug.LogError($"AdPlayManager is not exist in scene");
                return;
            }

            if (isInitialized || currentTryCount > 3)
                return;

            if (currentTryCount != 0)//if its not first initialize, wait for a delay
                await Task.Delay(1000);

            initializeState = InitializeState.Initializing;
            Instance.adPlayBatchSender.Initialize();

            Instance.activeAds.Clear();
            Instance.engagementData.Clear();

            AdPlayCacheService.Initialize();

            await Instance.GetAds();
            currentTryCount++;

            if (isInitialized)
                OnGetAdsComplete?.Invoke();

        }

        private async void Update()
        {
            if (initializeState == InitializeState.Initializing)
                return;

            if (Application.internetReachability == NetworkReachability.NotReachable)
            {

            }
            else
            {
                if (initializeState == InitializeState.FailedToInitialize)
                {
                    initializeState = InitializeState.Initializing;
                    await Initialize();
                }
            }
        }

        //get ads and download textures and sounds
        private async Task GetAds()
        {
            try
            {
                var publicIpResponse = await request.PublicIp();
                AdPlayUtility.PublicIp = publicIpResponse.IsSuccess ? publicIpResponse.Result : $"";
                AdPlayUtility.GoogleAdId = AdvertisingId.GetAdvertisingId();

                var adsResponse = await request.ShowAds();
                if (!adsResponse.IsSuccess)
                {
#if UNITY_EDITOR
                    Debug.LogError($"Get ads from ad play not success Code: {adsResponse.Code} - Error: {adsResponse.Error}");

#endif
                    isInitialized = false;
                    initializeState = InitializeState.FailedToInitialize;
                    return;
                }
#if UNITY_EDITOR
                foreach (var ad in adsResponse.Result)
                {
                    ad.Log();
                }
#endif
                activeAds.SetActiveCreatives(adsResponse.Result);

                if (adsResponse.IsSuccess)
                {
                    foreach (var ad in adsResponse.Result)
                    {
                        if (ad.AdPlacementType == AdPlacementType.ProductPlacement)
                        {
                            if (AdPlayCacheService.GetTexture(ad.AssetUrl, out var cacheTexture))
                            {
                                activeAds.AddCreative(ad, cacheTexture, null);
                            }
                            else
                            {
                                var textureResponse = await request.GetTextureDirectly(ad.AssetUrl);
                                if (textureResponse.IsSuccess)
                                {
                                    activeAds.AddCreative(ad, textureResponse.Result, null);

                                    AdPlayCacheService.AddTexture(ad.AssetUrl, textureResponse.Result);
                                }
                            }
                        }
                        else if (ad.AdPlacementType == AdPlacementType.VoicePlacement)
                        {
                            var audioResponse = await request.GetAudioDirectly(ad.AssetUrl);
                            if (audioResponse.IsSuccess)
                            {
                                AdPlayCacheService.AddSound(ad, audioResponse.Result);
                            }
                        }
                        else if (ad.AdPlacementType == AdPlacementType.VideoPlacement)
                        {

                        }
                    }

                    AdPlayCacheService.RemoveOldCache(activeAds.GetUrls());


                    isInitialized = true;
                    initializeState = InitializeState.Initialized;
                    Debug.Log($"Ad play sdk initialized");

                    return;
                }

                initializeState = InitializeState.FailedToInitialize;
            }
            catch (Exception ex)
            {
                Debug.LogError($"Adplay has error: {ex.Message}");
            }
        }


        public static async Task<AdRequestInfo> GetInterstitialSound(CreativeShowType creativeShowType)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await Instance.interstitialSound.GetAd(creativeShowType);
        }

        /// <summary>
        /// Show ad play pop up button
        /// </summary>
        /// <param name="template"></param>
        /// <param name="onButtonClick"></param>
        /// <returns></returns>
        public static async Task<AdRequestInfo> GetPopUpButton(AdPlayTemplate template, CreativeShowType creativeShowType, Action<int> onButtonClick)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            var result = await Instance.popUpButton.GetAd(template, creativeShowType, onButtonClick);
            return result;
        }

        /// <summary>
        /// Show ad play splash
        /// </summary>
        /// <param name="template">The parent view is either a canvas or a child of a canvas.</param>
        /// <returns></returns>
        public static async Task<AdRequestInfo> GetSplash(AdPlayTemplate template, CreativeShowType creativeShowType)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await Instance.splash.GetAd(template, creativeShowType);
        }

        /// <summary>
        /// Show ad play banner
        /// </summary>
        /// <param name="template">The parent view is either a canvas or a child of a canvas.</param>
        /// <returns></returns>
        public static async Task<AdRequestInfo> GetBanner(AdPlayTemplate template, CreativeShowType creativeShowType, BannerPlaceType bannerPlaceType)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await Instance.banner.GetAd(template, creativeShowType, bannerPlaceType);
        }

        public static async Task<AdRequestInfo> GetPopUp(AdPlayTemplate template, int relatedAdId)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await Instance.popUp.GetAd(template, relatedAdId);
        }


    }

    public enum InitializeState
    {
        NotInitialized,
        Initializing,
        FailedToInitialize,
        Initialized
    }
}
