using System;
using System.Collections.Generic;
using System.Globalization;
using Firebase.Crashlytics;
using UnityEngine;


namespace Guru
{
    
    
    /// <summary>
    /// MAX KeyWord管理器
    /// </summary>
    public class KeywordsManager
    {
        public const string Version = "0.4.0"; 
        
        public static readonly string Tag = "[KWM]";

        public static readonly DateTime BaseDate = new DateTime(1970, 1, 1).ToUniversalTime();

        /// <summary>
        /// 日期转时间戳 (Ticks)
        /// </summary>
        /// <param name="date"></param>
        /// <returns></returns>
        public static long DateToTicks(DateTime date) => (date.ToUniversalTime() - BaseDate).Ticks;

        /// <summary>
        /// 时间戳 (Ticks) 转日期
        /// </summary>
        /// <param name="stamp"></param>
        /// <returns></returns>
        public static DateTime TicksToDate(long stamp) => BaseDate.AddTicks(stamp);
        
        /// <summary>
        /// 首次安装时间
        /// </summary>
        public static DateTime FirstInstallDate
        {
            get
            {
                var key = nameof(FirstInstallDate);
                if (PlayerPrefs.HasKey(key))
                {
                    var value = PlayerPrefs.GetString(key, "");
                    if (!string.IsNullOrEmpty(value) && long.TryParse(value, out var ticks))
                    {
                        return TicksToDate(ticks);
                    }
                }
                
                Debug.Log($"{Tag} Can't find first install date, using NOW!!");
                FirstInstallDate = UTCNow;
                return UTCNow;
            }

            set => PlayerPrefs.SetString(nameof(FirstInstallDate), DateToTicks(value).ToString(new CultureInfo("en")));
        }
        public static DateTime UTCNow => DateTime.Now.ToUniversalTime();
        

        /// <summary>
        /// 当前的LT
        /// </summary>
        public static int CurrentLT => Instance?.GetLTValue() ?? -1;
        
        private static KeywordsManager _instance;
        public static KeywordsManager Instance {
            get {
                if(_instance == null) _instance = new KeywordsManager();
                return _instance;
            }
        }
        
        public static readonly List<int> ItDays = new List<int>()
        {
            0, 1, 2, 3, 4, 5, 6, 14, 30, 60, 90, 120, 180
        };
        
        private static string _badsWaterfallName = "null";
        private static string _iadsWaterfallName = "null";
        private static string _radsWaterfallName = "null";

        // Banner 瀑布流名称
        public static string BadsWaterfallName => _badsWaterfallName;
        // Interstital 瀑布流名称
        public static string IadsWaterfallName => _iadsWaterfallName;
        // Reward 瀑布流名称
        public static string RadsWaterfallName => _radsWaterfallName;
        /// <summary>
        /// 是否具有用户标签
        /// </summary>
        public static bool IsUserMarked
        {
            get
            {
                if(!PlayerPrefs.HasKey(nameof(IsUserMarked))) return false;
                return !string.IsNullOrEmpty(PlayerPrefs.GetString(nameof(IsUserMarked), ""));
            }
            set => PlayerPrefs.SetString(nameof(IsUserMarked), value? "marked": "");
        }

        /// <summary>
        /// 是否是付费用户
        /// 在用户执行任何一次购买的时候需要更新该接口
        /// </summary>
        public static bool IsIapUser
        {
            get => PlayerPrefs.GetInt(nameof(IsIapUser), 0) == 1;
            set => PlayerPrefs.SetInt(nameof(IsIapUser), value ? 1 : 0);
        }


        #region 初始化
        
        /// <summary>
        /// 安装服务
        /// </summary>
        /// <param name="isIAPUser">标记用户是否为付费用户</param>
        /// <param name="finishedLevels">当前完成关卡数. 不做关卡过滤时. 默认赋值0即可</param>
        public static void Install(bool isIAPUser = false, int finishedLevels = 0)
        {
            try
            {
                // 首先检查用户属性
                if (finishedLevels > 0 && !CheckTargetUser(finishedLevels))
                {
                    Debug.Log($"{Tag} User is not new installing. Skip user....");
                    return;
                }
                
                if (KeywordsConfig.Enabled()) // 云控开关, 如果不需要云控, 可注释此行
                {
                    Instance.Init();
                    if (!IsIapUser && isIAPUser) IsIapUser = true; // 判断未赋值时, 更新此变量
                }
            }
            catch (Exception e)
            {
                Crashlytics.LogException(e);
            }
        }

        /// <summary>
        /// 初始化
        /// </summary>
        private void Init()
        {
            var lt = GetLTValue();  // 初始化立即更新LT
            Debug.Log($"{Tag} is inited. LT:{lt}"); // 显示启动日志
            SetupMaxCallbacks();
        }


        private void SetupMaxCallbacks()
        {
            MaxSdkCallbacks.OnSdkInitializedEvent += OnMaxSdkInitializedCallBack;
            
            MaxSdkCallbacks.Banner.OnAdLoadedEvent += OnBannerLoaded;
            MaxSdkCallbacks.Banner.OnAdLoadFailedEvent += OnBannerLoadFailed;
            MaxSdkCallbacks.Interstitial.OnAdLoadedEvent += OnInterstitialLoaded;
            MaxSdkCallbacks.Interstitial.OnAdLoadFailedEvent += OnInterstitialLoadFailed;
            MaxSdkCallbacks.Rewarded.OnAdLoadedEvent += OnRewardedLoaded;
            MaxSdkCallbacks.Rewarded.OnAdLoadFailedEvent += OnRewardedLoadedFailed;
        }
        
        /// <summary>
        /// 检查是否是目标用户
        /// </summary>
        /// <param name="finishedLevels"></param>
        /// <returns></returns>
        public static bool CheckTargetUser(int finishedLevels)
        {
            // 如果用户已经被标记, 则继续上报
            if (IsUserMarked) return true;

            // 用户未标记, 则根据完成的关卡判断用户是否是新用户
            // 新用户则给标记
            if (finishedLevels <= 2)
            {
                IsUserMarked = true;
                Debug.Log($"{Tag} User is new installing. Mark user as target....");
                return true;
            }
            
            // 用户未标记且已经开始过游戏了, 则视为老用户
            return false;
        }
        
        #endregion
        
        #region Keywords
        
        /// <summary>
        /// 上报关键字
        /// </summary>
        private void ReportKeyword()
        {
            var lt = GetLTValue();
            bool paid = IsIapUser;
            string version = Application.version;
            var keywords = new [] { $"lt:{lt}", $"paid:{paid.ToString().ToLower()}", $"app_version:{version}" };
            SetMaxKeywords(keywords);
        }
        
        /// <summary>
        /// 获取LT值
        /// </summary>
        /// <returns></returns>
        private int GetLTValue(int days = 0)
        {
            // Debug.Log($"{Tag} Get first install date: {FirstInstallDate}");
            if(0 == days) days = (int)(UTCNow - FirstInstallDate).TotalDays;
            if(days > ItDays[ItDays.Count-1]) return ItDays[ItDays.Count-1];
            
            for (int i = 0; i < ItDays.Count; i++)
            {
                if (days < ItDays[i])
                {
                    if (i > 0)
                    {
                        return ItDays[i - 1];
                    }
                    else
                    {
                        return ItDays[0];
                    }
                }
            }
            return ItDays[0];
        }


        /// <summary>
        /// 设置Keywords
        /// </summary>
        /// <param name="keywords"></param>
        private void SetMaxKeywords(string[] keywords)
        {
            if ( null == keywords ) return;
            Debug.Log($"{Tag} set keywords: [{string.Join(",", keywords)}]");
            MaxSdk.TargetingData.ClearAll();
            MaxSdk.TargetingData.Keywords = keywords;
        }
        

        #endregion
        
        #region WaterfallName

        /// <summary>
        /// Banner WaterfallInfo
        /// </summary>
        /// <param name="waterfallInfo"></param>
        private void OnGetBannerWaterInfo(MaxSdkBase.WaterfallInfo waterfallInfo)
        {
            _badsWaterfallName = waterfallInfo.Name;
        }

        /// <summary>
        /// IV WaterfallInfo
        /// </summary>
        /// <param name="waterfallInfo"></param>
        private void OnGetIVWaterInfo(MaxSdkBase.WaterfallInfo waterfallInfo)
        {
            _iadsWaterfallName = waterfallInfo.Name;
        }
        
        /// <summary>
        /// RV WaterfallInfo
        /// </summary>
        /// <param name="waterfallInfo"></param>
        private void OnGetRVWaterInfo(MaxSdkBase.WaterfallInfo waterfallInfo)
        {
            _radsWaterfallName = waterfallInfo.Name;
        }
        
        #endregion
        
        #region Max 生命周期监控

        private void OnMaxSdkInitializedCallBack(MaxSdkBase.SdkConfiguration obj)
        {
            ReportKeyword();
        }
        
        
        private void OnBannerLoaded(string adUnitId, MaxSdkBase.AdInfo adInfo)
        {
            OnGetBannerWaterInfo(adInfo.WaterfallInfo);
        }
        
        private void OnBannerLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
        {
            OnGetBannerWaterInfo(errorInfo.WaterfallInfo);
        }
        
        private void OnRewardedLoadedFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
        {
            OnGetRVWaterInfo(errorInfo.WaterfallInfo);
        }

        private void OnRewardedLoaded(string adUnitId, MaxSdkBase.AdInfo adInfo)
        {
            OnGetRVWaterInfo(adInfo.WaterfallInfo);
        }

        private void OnInterstitialLoadFailed(string adUnitId, MaxSdkBase.ErrorInfo errorInfo)
        {
            OnGetIVWaterInfo(errorInfo.WaterfallInfo);
        }

        private void OnInterstitialLoaded(string adUnitId, MaxSdkBase.AdInfo adInfo)
        {
            OnGetIVWaterInfo(adInfo.WaterfallInfo);
        }

        #endregion
        
        #region Unit Test

#if UNITY_EDITOR
        
        public static void DebugKeywords(string[] kw) => Instance?.SetMaxKeywords(kw);

        /// <summary>
        /// LT取值测试
        /// </summary>
        [UnityEditor.MenuItem("Test/Test LT")]
        public static void TestFetchLT()
        {
            var days = 0;
            days = 0;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 1;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 2;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 5;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 12;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 15;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 55;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 80;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 179;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
            days = 365;
            Debug.Log($"Days: {days} => TL: {Instance.GetLTValue(days)}");
        }

#endif

        #endregion

    }
    
    #region 云控参数
    
    [Serializable]
    internal class KeywordsConfig
    {
        public const string KEY = "keywords_config";
        public bool enable = false;
        
        /// <summary>
        /// 获取功能是否开启
        /// </summary>
        /// <returns></returns>
        public static bool Enabled()
        {
            var cfg = Get();
            return cfg?.enable ?? false;
        }

        public static KeywordsConfig Get()
        {
            try
            {
                string raw = GetRemoteValue(KEY);
                if (!string.IsNullOrEmpty(raw))
                {
                    return JsonUtility.FromJson<KeywordsConfig>(raw);
                }
            }
            catch (Exception e)
            {
                Debug.LogError(e);
                Crashlytics.LogException(e);
            }
            
            return new KeywordsConfig();  // 返回默认值
        }


        /// <summary>
        /// 获取Online值
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        private static string GetRemoteValue(string key)
        {
            var remote = Firebase.RemoteConfig.FirebaseRemoteConfig.DefaultInstance;
            if (remote != null)
            {
                try
                {
                    return remote.GetValue(key).StringValue;
                }
                catch (Exception e)
                {
                    Crashlytics.LogException(e);
                }
            }

            return "";
        }


    }
    
    #endregion
    
}