using Alibabacloud.Rum.Unity.Integrations;
using Alibabacloud.Rum.Unity.Logs;
using Alibabacloud.Rum.Unity.Rum;
using UnityEngine;
using UnityEngine.Serialization;
using System;
using System.Collections.Generic;

namespace Alibabacloud.Rum.Unity
{
    public class AlibabacloudOptions : ScriptableObject
    {
        /// <summary>
        /// Relative to Assets/Resources
        /// </summary>
        public const string ConfigRootFolder = "Alibabacloud";

        /// <summary>
        /// Main AlibabaCloud config name for Unity
        /// </summary>
        public const string ConfigName = "AlibabacloudOptions";

        /// <summary>
        /// Path for the config for Unity
        /// </summary>
        public static string GetConfigPath(string? notDefaultConfigName = null)
            => $"Assets/Resources/{ConfigRootFolder}/{notDefaultConfigName ?? ConfigName}.asset";

        [field: SerializeField] public bool Enabled { get; set; } = true;

        [field: SerializeField] public string? Endpoint { get; set; }

        [field: SerializeField] public string? ServiceId { get; set; }
        [field: SerializeField] public string? Workspace { get; set; }
        [field: SerializeField] public bool EnableNativeSDKLogDebug { get; set; } = true;

        [field: SerializeField] public bool EnableLogDebouncing { get; set; } = false;

        [field: SerializeField]
        public int DebounceTimeLog { get; set; } = (int)TimeSpan.FromSeconds(1).TotalMilliseconds;

        [field: SerializeField]
        public int DebounceTimeWarning { get; set; } = (int)TimeSpan.FromSeconds(1).TotalMilliseconds;

        [field: SerializeField]
        public int DebounceTimeError { get; set; } = (int)TimeSpan.FromSeconds(1).TotalMilliseconds;

        [field: SerializeField] public double TracesSampleRate { get; set; } = 0;
        [field: SerializeField] public bool AutoStartupTraces { get; set; } = true;
        [field: SerializeField] public bool AutoSceneLoadTraces { get; set; } = true;
        [field: SerializeField] public bool AutoAwakeTraces { get; set; } = false;

        [field: SerializeField] public bool AutoSessionTracking { get; set; } = true;

        /// <summary>
        /// Interval in milliseconds a session terminates if put in the background.
        /// </summary>
        [field: SerializeField]
        public int AutoSessionTrackingInterval { get; set; } = (int)TimeSpan.FromSeconds(30).TotalMilliseconds;

        /// <summary>
        /// Enable automatic view (scene) tracking. When enabled, scene changes will be automatically
        /// tracked as RUM views with scene path as view ID and scene name as view name.
        /// </summary>
        [field: SerializeField] public bool AutomaticSceneTracking { get; set; } = true;

        [field: SerializeField] public string ReleaseOverride { get; set; } = string.Empty;
        [field: SerializeField] public string EnvironmentOverride { get; set; } = string.Empty;
        [field: SerializeField] public bool AttachStacktrace { get; set; }
        [field: SerializeField] public bool AttachScreenshot { get; set; }
        [field: SerializeField] public int ScreenshotCompression { get; set; } = 75;

        [field: SerializeField] public bool AttachViewHierarchy { get; set; } = false;
        [field: SerializeField] public int MaxViewHierarchyRootObjects { get; set; } = 100;
        [field: SerializeField] public int MaxViewHierarchyObjectChildCount { get; set; } = 20;
        [field: SerializeField] public int MaxViewHierarchyDepth { get; set; } = 10;

        [field: SerializeField] public bool EnableStructuredLogging { get; set; } = false;
        [field: SerializeField] public bool StructuredLogOnDebugLog { get; set; } = false;
        [field: SerializeField] public bool StructuredLogOnDebugLogWarning { get; set; } = true;
        [field: SerializeField] public bool StructuredLogOnDebugLogAssertion { get; set; } = true;
        [field: SerializeField] public bool StructuredLogOnDebugLogError { get; set; } = true;
        [field: SerializeField] public bool StructuredLogOnDebugLogException { get; set; } = true;
        
        /// <summary>
        /// Enable network request tracking. When enabled, network requests will be automatically instrumented
        /// and tracked as RUM resources.
        /// </summary>
        [field: SerializeField] public bool EnableNetworkTracking { get; set; } = true;
        
        /// <summary>
        /// Sample rate for network requests. Value between 0.0 and 1.0.
        /// 1.0 means all requests are tracked, 0.5 means 50% of requests are tracked.
        /// </summary>
        [field: SerializeField] public double NetworkSampleRate { get; set; } = 1.0;
        
        /// <summary>
        /// URL allowlist patterns. If provided, only URLs containing these patterns will be tracked.
        /// Empty array means all URLs are allowed (subject to blocklist and other filters).
        /// </summary>
        [field: SerializeField] public string[] NetworkUrlAllowlist { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// URL blocklist patterns. URLs containing these patterns will not be tracked.
        /// </summary>
        [field: SerializeField] public string[] NetworkUrlBlocklist { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// Whether to capture request body size in bytes.
        /// </summary>
        [field: SerializeField] public bool CaptureRequestBodySize { get; set; } = true;
        
        /// <summary>
        /// Whether to capture response body size in bytes.
        /// </summary>
        [field: SerializeField] public bool CaptureResponseBodySize { get; set; } = true;
        
        /// <summary>
        /// Whether to capture request headers. When enabled, request headers will be included in resource attributes.
        /// </summary>
        [field: SerializeField] public bool CaptureRequestHeaders { get; set; } = false;
        
        /// <summary>
        /// Whether to capture response headers. When enabled, response headers will be included in resource attributes.
        /// </summary>
        [field: SerializeField] public bool CaptureResponseHeaders { get; set; } = false;
        
        /// <summary>
        /// Request header names to capture. If empty, all headers are captured (when CaptureRequestHeaders is enabled).
        /// If provided, only headers matching these names will be captured.
        /// </summary>
        [field: SerializeField] public string[] NetworkRequestHeaderAllowlist { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// Request header names to exclude from capture. Headers matching these names will not be captured.
        /// </summary>
        [field: SerializeField] public string[] NetworkRequestHeaderBlocklist { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// Response header names to capture. If empty, all headers are captured (when CaptureResponseHeaders is enabled).
        /// If provided, only headers matching these names will be captured.
        /// </summary>
        [field: SerializeField] public string[] NetworkResponseHeaderAllowlist { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// Response header names to exclude from capture. Headers matching these names will not be captured.
        /// </summary>
        [field: SerializeField] public string[] NetworkResponseHeaderBlocklist { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// HTTP methods to track. If all are false, all methods are tracked.
        /// </summary>
        [field: SerializeField] public bool TrackHttpGet { get; set; } = false;
        [field: SerializeField] public bool TrackHttpPost { get; set; } = false;
        [field: SerializeField] public bool TrackHttpPut { get; set; } = false;
        [field: SerializeField] public bool TrackHttpDelete { get; set; } = false;
        [field: SerializeField] public bool TrackHttpPatch { get; set; } = false;
        [field: SerializeField] public bool TrackHttpHead { get; set; } = false;
        [field: SerializeField] public bool TrackHttpOptions { get; set; } = false;
        
        /// <summary>
        /// HTTP status code ranges to track. Format: "200-299", "400-499", etc.
        /// If empty, all status codes are tracked. If provided, only requests with status codes in these ranges will be tracked.
        /// </summary>
        [field: SerializeField] public string[] NetworkStatusCodeRanges { get; set; } = Array.Empty<string>();
        
        /// <summary>
        /// Enable trace context propagation for distributed tracing.
        /// </summary>
        [field: SerializeField] public bool EnableTraceContext { get; set; } = false;
        
        /// <summary>
        /// Trace context configurations per URL pattern.
        /// Each entry specifies a URL pattern and the trace standard (W3C or SkyWalking) to use for that pattern.
        /// If empty, no trace context is injected.
        /// </summary>
        [field: SerializeField] public TraceContextConfig[] TraceContextConfigs { get; set; } = Array.Empty<TraceContextConfig>();
        

        // [field: SerializeField] public bool AnrDetectionEnabled { get; set; } = true;
        //
        // [field: SerializeField]
        // public int AnrTimeout { get; set; } = (int)TimeSpan.FromSeconds(5).TotalMilliseconds;

        
        [field: SerializeField] public bool Il2CppLineNumberSupportEnabled { get; set; } = true;
        
        /// <summary>
        /// Enable output of IL2CPP symbol mapping files for crash symbolication.
        /// When enabled, the build process will generate LineNumberMappings.json files
        /// that can be uploaded to Alibabacloud for better stack trace symbolication.
        /// </summary>
        [field: SerializeField] public bool OutputSymbols { get; set; } = false;
        
        /// <summary>
        /// Enable automatic upload of symbol files to Alibabacloud after build.
        /// Requires OutputSymbols to be enabled and valid upload credentials to be configured.
        /// </summary>
        [field: SerializeField] public bool UploadSymbolsAfterBuild { get; set; } = false;
        
        /// <summary>
        /// API endpoint for uploading symbol files. Leave empty to use default endpoint.
        /// </summary>
        [field: SerializeField] public string SymbolUploadEndpoint { get; set; } = string.Empty;
        
        /// <summary>
        /// API key or access token for uploading symbol files.
        /// </summary>
        [field: SerializeField] public string SymbolUploadApiKey { get; set; } = string.Empty;
        
        // [field: SerializeField] public AlibabacloudOptionsConfiguration? OptionsConfiguration { get; set; }
        
        [field: SerializeField] public bool Debug { get; set; } = true;
        // [field: SerializeField] public bool DebugOnlyInEditor { get; set; } = false;

        [field: SerializeField]
        public AlibabacloudLogLevel DiagnosticLevel { get; set; } = AlibabacloudLogLevel.Warning;
        
        
        public Dictionary<LogType, bool> CaptureStructuredLogsForLogType { get; set; }
     
        /// <summary>
        /// Loads the ScriptableAlibabacloudUnityOptions from <c>Resource</c>.
        /// </summary>
        /// <returns>The <c>AlibabacloudUnityOptions</c> generated from the <c>ScriptableAlibabacloudUnityOptions</c></returns>
        public static AlibabacloudOptions? LoadAlibabacloudUnityOptions()
        {
            var options =
                Resources.Load<AlibabacloudOptions>($"{ConfigRootFolder}/{ConfigName}");
            if (options is not null)
            {
                options.CaptureStructuredLogsForLogType = new Dictionary<LogType, bool>()
                {
                    [LogType.Log] = options.StructuredLogOnDebugLog,
                    [LogType.Warning] = options.StructuredLogOnDebugLogWarning,
                    [LogType.Assert] = options.StructuredLogOnDebugLogAssertion,
                    [LogType.Error] = options.StructuredLogOnDebugLogError,
                    [LogType.Exception] = options.StructuredLogOnDebugLogException
                };
                
                // We need to set up logging here because the configure callback might have changed the debug options.
                // Without setting up here we might miss out on logs between option-loading (now) and Init - i.e. native configuration
                options.SetupUnityLogging();
                
            }

            return options;
        }

        public AlibabacloudOptions()
        {
            CaptureStructuredLogsForLogType = new Dictionary<LogType, bool>();
        }
        
        private volatile IDiagnosticLogger? _diagnosticLogger;
        /// <summary>
        /// The implementation of the logger.
        /// </summary>
        /// <remarks>
        /// The <see cref="Debug"/> flag has to be switched on for this logger to be used at all.
        /// When debugging is turned off, this property is made null and any internal logging results in a no-op.
        /// </remarks>
        public IDiagnosticLogger? DiagnosticLogger
        {
            get => _diagnosticLogger;
            set
            {
                if (value is null)
                {
                    _diagnosticLogger?.LogDebug(
                        "Alibabacloud will not emit SDK debug messages because debug mode has been turned off.");
                }
                else
                {
                    _diagnosticLogger?.LogInfo("Replacing current logger with: '{0}'.", value.GetType().Name);
                }

                _diagnosticLogger = value;
            }
        }

    }
}