

using System.Collections;

namespace Guru
{
	using System;
	using System.Collections.Generic;
	using com.adjust.sdk;
	using Facebook.Unity;
	using Firebase.Analytics;
	using Firebase.Crashlytics;
	
	//打点模块初始化和基础接口封装
	public static partial class Analytics
	{
		public class EventSetting
		{
			public bool EnableFirebaseAnalytics = false;
			public bool EnableAdjustAnalytics = false;
			public bool EnableFacebookAnalytics = false;
		}

		private static EventSetting _defaultEventSetting;
		
		private static bool _isInited;				//Analytics是否初始化完成
		public static bool EnableDebugAnalytics;	//允许Debug包上报打点

		public static bool IsDebugMode => PlatformUtil.IsDebug();
		
		private static bool IsEnable 
		{
			get
			{
				//Firebase服务没有初始化完成不上报打点
				if (!FirebaseUtil.IsFirebaseInitialized)
					return false;
				
				//Analytics没有初始化不上报打点
				if (!_isInited)
					return false;

				//开发环境打点不上报
				if (IsDebugMode && !EnableDebugAnalytics)
					return false;

				return true;
			}
		}
		
		#region 初始化

		public static void InitAnalytics()
		{
			if (_isInited) return;
			_isInited = true;
			
			// -------- 初始化 Exception ----------
			CrashlyticsAgent.Install();
			
			// ------- 初始化自打点 ----------
			InstallGuruAnalytics(IsDebug);
			
			if (_defaultEventSetting == null)
			{
				var analyticsSetting = GuruSettings.Instance.AnalyticsSetting;
				_defaultEventSetting = new EventSetting
				{
					EnableFirebaseAnalytics = analyticsSetting.EnalbeFirebaseAnalytics,
					EnableFacebookAnalytics = analyticsSetting.EnalbeFacebookAnalytics,
					EnableAdjustAnalytics = analyticsSetting.EnalbeAdjustAnalytics
				};
			}
			
			FirebaseUtil.onInitComplete += OnFirebaseCompleted;
		}

		private static void OnFirebaseCompleted(bool success)
		{
			FirebaseUtil.onInitComplete -= OnFirebaseCompleted;

			if (success)
			{
				Crashlytics.IsCrashlyticsCollectionEnabled = true;
				if (_defaultEventSetting.EnableFirebaseAnalytics)
				{
					FirebaseAnalytics.SetAnalyticsCollectionEnabled(true);
					FirebaseAnalytics.SetSessionTimeoutDuration(new TimeSpan(0, 30, 0));
					SetUserProperty(FirebaseAnalytics.UserPropertySignUpMethod, "Google");
					SetUserProperty(PropertyDeviceID, IPMConfig.IPM_DEVICE_ID);
					// SetUserProperty(PropertyFirstOpenTime, FirstOpenTime);
				}
			}
		}

		#endregion

		#region 屏幕(场景)名称

		public static void SetCurrentScreen(string screenName, string className)
		{
			Log.I(TAG,$"SetCurrentScreen -> screenName:{screenName}, className:{className}");
			GuruAnalytics.SetScreen(screenName);
			
			if (!IsEnable) return;
			FirebaseAnalytics.LogEvent(FirebaseAnalytics.EventScreenView,
				new Parameter(FirebaseAnalytics.ParameterScreenClass, className),
				new Parameter(FirebaseAnalytics.ParameterScreenName, screenName)
			);
		}

		#endregion

		#region 用户属性上报

		/// <summary>
		/// Firebase上报用户ID
		/// </summary>
		/// <param name="userID">通过Auth认证地用户ID</param>
		public static void SetUserIDProperty(string userID)
		{
			Log.I(TAG,$"SetUserIDProperty -> userID:{userID}");
			if (!IsEnable) return;
			
			FirebaseAnalytics.SetUserId(userID);
		}

		/// <summary>
		/// Firebase上报用户属性
		/// </summary>
		public static void SetUserProperty(string propertyName, string propertyValue)
		{
			Log.I(TAG,$"SetUserProperty -> propertyName:{propertyName}, propertyValue:{propertyValue}");
        
			if (!IsEnable)
				return;
			
			FirebaseAnalytics.SetUserProperty(propertyName, propertyValue);
			CustomSetUserProperty(propertyName, propertyValue);
		}

		#endregion

		#region 打点上报

		/// <summary>
		/// 打点上报
		/// </summary>
		/// <param name="eventName"></param>
		/// <param name="eventSetting"></param>
		internal static void LogEvent(string eventName, EventSetting eventSetting = null)
		{
			Log.I(TAG, $"eventName:{eventName}");
			CustomLogEvent(eventName); // 自定义打点上报
			CheckLogCache(eventName, null, eventSetting); // log缓存和消费
			
			if (!IsEnable) return;

			eventSetting ??= _defaultEventSetting;
			
			if (eventSetting.EnableFirebaseAnalytics)
			{
				FirebaseAnalytics.LogEvent(eventName);
			}
			
			if (eventSetting.EnableAdjustAnalytics)
			{
				Adjust.trackEvent(CreateAdjustEvent(eventName));
			}

			if (eventSetting.EnableFacebookAnalytics)
			{
				FBService.LogEvent(eventName);
			}
		}

		/// <summary>
		/// 打点上报 (带参数)
		/// </summary>
		/// <param name="eventName"></param>
		/// <param name="extras"></param>
		/// <param name="eventSetting"></param>
		internal static void LogEvent(string eventName, Dictionary<string, dynamic> extras, EventSetting eventSetting = null) 
		{
			Log.I(TAG, $"eventName:{eventName}, params:{string.Join(",", extras)}");
			CustomLogEvent(eventName, extras); // 自定义打点上报

			CheckLogCache(eventName, extras, eventSetting); // log缓存和消费
			
			if (!IsEnable) return;

			if (extras == null)
			{
				LogEvent(eventName, eventSetting); // 防空判定
				return;
			}

			eventSetting ??= _defaultEventSetting;
			if (eventSetting.EnableFirebaseAnalytics)
			{
				List<Parameter> parameters = new List<Parameter>();
				foreach (var kv in extras)
				{
					if(kv.Value is string strValue)
						parameters.Add(new Parameter(kv.Key, strValue));
					else if (kv.Value is bool boolValue)
						parameters.Add(new Parameter(kv.Key, boolValue ? "true" : "false"));
					else if (kv.Value is int intValue)
						parameters.Add(new Parameter(kv.Key, intValue));
					else if (kv.Value is long longValue)
						parameters.Add(new Parameter(kv.Key, longValue));
					else if (kv.Value is float floatValue)
						parameters.Add(new Parameter(kv.Key, floatValue));
					else if (kv.Value is double doubleValue)
						parameters.Add(new Parameter(kv.Key, doubleValue));
					else if (kv.Value is decimal decimalValue)
						parameters.Add(new Parameter(kv.Key, decimal.ToDouble(decimalValue)));
					else
						parameters.Add(new Parameter(kv.Key, kv.Value.ToString()));
					
				}
				
				FirebaseAnalytics.LogEvent(eventName, parameters.ToArray());
			}

			Dictionary<string, object> dict = new Dictionary<string, object>();
			GuruSDKUtils.MergeDictionary(dict, extras);
			
			if (eventSetting.EnableAdjustAnalytics)
			{
				AdjustEvent adjustEvent = Analytics.CreateAdjustEvent(eventName);
				if (adjustEvent != null)
				{
					if (dict.Count > 0)
					{
						foreach (var kv in dict)
						{
							adjustEvent.AddEventParameter(kv.Key, kv.Value.ToString());
						}
					}
					Adjust.trackEvent(adjustEvent);
				}
			}
			
			if (eventSetting.EnableFacebookAnalytics)
			{
				FBService.LogEvent(eventName, null, dict);
			}
		}

		/// <summary>
		/// 上报 Adjust 事件
		/// </summary>
		/// <param name="eventName"></param>
		/// <param name="productId"></param>
		/// <param name="receipt"></param>
		/// <param name="data"></param>
		/// <param name="usdPrice"></param>
		/// <param name="transactionId"></param>
		/// <param name="purchaseToken"></param>
		/// <returns></returns>
		internal static bool LogAdjustRevenueEvent(string eventName, double usdPrice, 
			string productId = "", string transactionId = "", string purchaseToken = "", string receipt = "", 
			Dictionary<string, object> data = null )
		{
			AdjustEvent adjustEvent = Analytics.CreateAdjustEvent(eventName);
			if (adjustEvent != null)
			{ 
				adjustEvent.setRevenue(usdPrice, USD);
				if (!string.IsNullOrEmpty(productId)) adjustEvent.setProductId(productId);
				if (!string.IsNullOrEmpty(transactionId)) adjustEvent.setTransactionId(transactionId);
				if (!string.IsNullOrEmpty(purchaseToken)) adjustEvent.setPurchaseToken(purchaseToken);
				if (!string.IsNullOrEmpty(receipt)) adjustEvent.setReceipt(receipt);

				if (data != null && data.Count > 0)
				{
					foreach (var kv in data)
					{
						adjustEvent.AddEventParameter(kv.Key, kv.Value.ToString());
					}
				}
				
				Adjust.trackEvent(adjustEvent);
				return true;
			}
			return false;
		}

		#endregion
		
		#region 通用打点

		/// <summary>
		/// 一般的事件上报通用接口
		/// </summary>
		/// <param name="key"></param>
		/// <param name="data"></param>
		/// <param name="setting"></param>
		public static void Track(string key, Dictionary<string, dynamic> data = null, EventSetting setting = null)
		{
			if (null != data)
			{
				LogEvent(key, data, setting);
			}
			else
			{
				LogEvent(key, setting);
			}
		}

		
		/// <summary>
		/// Crashlytics 上报 
		/// </summary>
		/// <param name="msg"></param>
		/// <param name="isException"></param>
		public static void LogCrashlytics(string msg, bool isException = true)
		{
			if (!_isInited) return;
			if (isException)
			{
				LogCrashlytics(new Exception(msg));
			}
			else
			{
				CrashlyticsAgent.Log(msg);
			}
		}
		
		
		public static void LogCrashlytics(Exception exp)
		{
			if (!_isInited) return;
			CrashlyticsAgent.LogException(exp);
		}

		#endregion

		#region 打点缓存

		private static Queue<SavedLog> _savedLogs;

		internal static Queue<SavedLog> SavedLogs
		{
			get
			{
				if (_savedLogs == null) _savedLogs = new Queue<SavedLog>(20);
				return _savedLogs;
			}
		}


		private static void CheckLogCache(string key, Dictionary<string, dynamic> data = null, EventSetting setting = null)
		{
			try
			{
				if (!_isInited)
				{
					if (data == null) data = new Dictionary<string, dynamic>();
					data["log_stamp"] = TimeUtil.GetCurrentTimeStamp().ToString();
					SavedLogs.Enqueue(new SavedLog(key, data, setting));
				}
				else
				{
					int len = SavedLogs.Count;
					if (len > 0)
					{
						while (SavedLogs.Count > 0)
						{
							var log = SavedLogs.Dequeue();
							LogEvent(log.key, log.data, log.setting);
						}
					}
				}
			}
			catch (Exception ex)
			{
				Crashlytics.LogException(ex);
			}
		}


		#endregion
	}


	internal class SavedLog
	{
		public string key;
		public Dictionary<string, dynamic> data;
		public Analytics.EventSetting setting;

		public SavedLog()
		{
		}

		public SavedLog(string _key, Dictionary<string, dynamic> _data = null, Analytics.EventSetting _setting = null)
		{
			key = _key;
			data = _data;
			setting = _setting;
		}
	}
}