using Sentry.Unity;
using Sentry;
using System.Collections.Generic;
using System;
using Combo.Platform;

#if !UNITY_WEBGL
using Newtonsoft.Json;
#endif

namespace Combo.Core
{
    public class SentryManager : SentryRuntimeOptionsConfiguration
    {
        /// Called at the player startup by SentryInitialization.
        /// You can alter configuration for the C# error handling and also
        /// native error handling in platforms **other** than iOS, macOS and Android.
        /// Learn more at https://docs.sentry.io/platforms/unity/configuration/options/#programmatic-configuration
        [System.Serializable]
        internal class Parameters
        {
#if UNITY_WEBGL
            // WebGL 不使用 Newtonsoft，需要手动映射 key
            public string sentry_webgl_dsn;
            public string sentry_unity_enabled;
            public string sentry_unity_debug_enabled;
            public string sentry_unity_send_default_pii_enabled;
            public string sentry_unity_attach_screenshot_enabled;
            public string sentry_unity_capture_logging_error_enabled;
            public string sentry_unity_max_breadcrumbs;
            public string sentry_unity_add_breadcrumb_log_types;

            public string dsn => sentry_webgl_dsn;
            public bool enabled =>
                !string.IsNullOrEmpty(sentry_unity_enabled) &&
                bool.TryParse(sentry_unity_enabled, out var v1) ? v1 : false;

            public bool debugEnabled =>
                !string.IsNullOrEmpty(sentry_unity_debug_enabled) &&
                bool.TryParse(sentry_unity_debug_enabled, out var v2) ? v2 : false;

            public bool sendDefaultPiiEnabled =>
                !string.IsNullOrEmpty(sentry_unity_send_default_pii_enabled) &&
                bool.TryParse(sentry_unity_send_default_pii_enabled, out var v3) ? v3 : false;

            public bool attachScreenShotEnabled =>
                !string.IsNullOrEmpty(sentry_unity_attach_screenshot_enabled) &&
                bool.TryParse(sentry_unity_attach_screenshot_enabled, out var v4) ? v4 : false;

            public bool captureLoggingErrorEnabled =>
                !string.IsNullOrEmpty(sentry_unity_capture_logging_error_enabled) &&
                bool.TryParse(sentry_unity_capture_logging_error_enabled, out var v5) ? v5 : false;

            public int maxBreadcrumbs
            {
                get
                {
                    if (string.IsNullOrEmpty(sentry_unity_max_breadcrumbs))
                        return 100;

                    if (int.TryParse(sentry_unity_max_breadcrumbs, out int v))
                        return v;

                    return 100;
                }
            }

            public string addBreadcrumbsForLogTypes => sentry_unity_add_breadcrumb_log_types;

#else
            // 其他平台继续使用 Newtonsoft
#if UNITY_ANDROID
            [JsonProperty("sentry_android_dsn")]
#elif UNITY_IOS
            [JsonProperty("sentry_ios_dsn")]
#elif UNITY_STANDALONE
            [JsonProperty("sentry_windows_dsn")]
#elif UNITY_OPENHARMONY
            [JsonProperty("sentry_harmonyos_dsn")]
#endif
            public string dsn;

            [JsonProperty("sentry_unity_enabled")]
            [JsonConverter(typeof(EmptyStringToBoolConverter))]
            public bool enabled = true;

            [JsonProperty("sentry_unity_debug_enabled")]
            [JsonConverter(typeof(EmptyStringToBoolConverter))]
            public bool debugEnabled = false;

            [JsonProperty("sentry_unity_send_default_pii_enabled")]
            [JsonConverter(typeof(EmptyStringToBoolConverter))]
            public bool sendDefaultPiiEnabled = true;

            [JsonProperty("sentry_unity_attach_screenshot_enabled")]
            public bool attachScreenShotEnabled = false;

            [JsonProperty("sentry_unity_max_breadcrumbs")]
            public int maxBreadcrumbs = 100;

            [JsonProperty("sentry_unity_add_breadcrumb_log_types")]
            public string addBreadcrumbsForLogTypes;

            [JsonProperty("sentry_unity_capture_logging_error_enabled")]
            public bool captureLoggingErrorEnabled = false;
#endif
        }

        public override void Configure(SentryUnityOptions options)
        {
#if UNITY_EDITOR
            options.Enabled = false;
            return;
#else
            var parameters = Native.GetParameters<Parameters>();

#if UNITY_ANDROID
            options.AndroidNativeSupportEnabled = true;
            options.NdkIntegrationEnabled = true;
            options.NdkScopeSyncEnabled = true;
#elif UNITY_IOS
            options.IosNativeSupportEnabled = true;
#elif UNITY_STANDALONE
            options.WindowsNativeSupportEnabled = true;
#endif

            if (string.IsNullOrEmpty(parameters.dsn))
            {
                Log.E("The sentry dsn must be is not empty!");
                return;
            }
            Log.I($"Start sentry, dsn = {parameters.dsn}");
            options.Enabled = parameters.enabled;
            options.Debug = parameters.debugEnabled;
            options.AttachScreenshot = false;
            options.AttachStacktrace = true;
            options.SendDefaultPii = parameters.sendDefaultPiiEnabled;
            options.Dsn = parameters.dsn;
            options.AttachScreenshot = parameters.attachScreenShotEnabled;
            options.MaxBreadcrumbs = parameters.maxBreadcrumbs;
            options.CaptureLogErrorEvents = parameters.captureLoggingErrorEnabled;
            options.AddBreadcrumbsForLogType = GetBreadcrumbsForLogType(parameters.addBreadcrumbsForLogTypes);
            options.DisableAnrIntegration();

#if UNITY_WEBGL
            // WebGL 平台：Sentry 在 BeforeSceneLoad 阶段初始化，
            // ConfigureScope 在 SDK 完全初始化前调用不会生效，
            // 所以使用 BeforeSend 回调来设置 tags
            var deviceId = Native.GetDeviceId();
            var distro = Native.GetDistro();
            var unityVersion = Version.SDKVersion;

            Log.I($"[SentryConfig] WebGL - deviceId={deviceId ?? "null"}, distro={distro ?? "null"}, unityVersion={unityVersion}");

            options.SetBeforeSend((sentEvent, _) =>
            {
                if (!string.IsNullOrEmpty(deviceId))
                {
                    sentEvent.SetTag("combo.device_id", deviceId);
                }
                if (!string.IsNullOrEmpty(distro))
                {
                    sentEvent.SetTag("combo.distro", distro);
                }
                sentEvent.SetTag("combo.sdk.unity_version", unityVersion);
                return sentEvent;
            });
#endif
#endif
        }

        internal static Dictionary<UnityEngine.LogType, bool> GetBreadcrumbsForLogType(string logTypesCsv)
        {
            Dictionary<UnityEngine.LogType, bool> result = new Dictionary<UnityEngine.LogType, bool>
            {
                { UnityEngine.LogType.Log, false },
                { UnityEngine.LogType.Warning, false },
                { UnityEngine.LogType.Assert, false },
                { UnityEngine.LogType.Error, false },
                { UnityEngine.LogType.Exception, false }
            };

            if (string.IsNullOrEmpty(logTypesCsv))
            {
                return result;
            }

            string[] logTypes = logTypesCsv.Split(',');
            foreach (string type in logTypes)
            {
                if (Enum.TryParse(type.Trim(), out UnityEngine.LogType logType))
                {
                    result[logType] = true;
                }
            }

            return result;
        }

        /// <summary>
        /// 设置 Sentry tags。
        /// WebGL 平台：此方法不会被调用，tags 在 Configure 的 BeforeSend 回调中设置。
        /// 其他平台：使用 ConfigureScope 设置 tags。
        /// </summary>
        internal static void Setup()
        {
#if !UNITY_EDITOR
            // TODO: Add more
            SentrySdk.ConfigureScope(scope =>
            {
                var variant = Native.GetVariant();
                if (!string.IsNullOrEmpty(variant))
                {
                    scope.SetTag("combo.variant", variant);
                }

                var subvariant = Native.GetSubvariant();
                if (!string.IsNullOrEmpty(subvariant))
                {
                    scope.SetTag("combo.subvariant", subvariant);
                }
                scope.SetTag("combo.device_id", Native.GetDeviceId());
                scope.SetTag("combo.distro", Native.GetDistro());
                scope.SetTag("combo.sdk.unity_version", Version.SDKVersion);
            });
#endif
        }
    }
}