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 AdPlayInterstitialSound interstitialSound;

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

        [SerializeField] private List<AdPlayActionInfo> actionInfos = new();

        private static List<AdPlayActionInfo> ActionInfos { get; set; }
        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;
            ActionInfos = Instance.actionInfos;
            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;
                }
                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)
                            {
                                activeAds.AddCreative(ad, null, 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()
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await Instance.interstitialSound.GetAd();
        }

        /// <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, Action onButtonClick)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            var result = await Instance.popUpButton.GetAd(template, 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)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await GetActionByType(AdType.Splash).GetAd(template);

        }

        /// <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)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await GetActionByType(AdType.Banner).GetAd(template);
        }
        /// <summary>
        /// Show ad play pop up
        /// </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> GetPopUp(AdPlayTemplate template)
        {
            if (Instance == null)
                return new AdRequestInfo(AdRequestResultState.AdPlayIsNotInitialized);
            return await GetActionByType(AdType.Popup).GetAd(template);
        }

        private static AdPlayAction GetActionByType(AdType type)
        {
            return ActionInfos.FirstOrDefault(a => a.AdType == type).AdPlayAction;
        }

    }

    [Serializable]
    public struct AdPlayActionInfo
    {
        [field: SerializeField] public AdType AdType { get; set; }
        [field: SerializeField] public AdPlayAction AdPlayAction { get; set; }
    }

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