using Alibabacloud.Rum.Unity.Rum;
using UnityEditor;
using UnityEngine;

namespace Alibabacloud.Rum.Unity.Editor
{
    internal static class NetworkTab
    {
        private static Vector2 _scrollPosition;
        private static bool _showUrlFilters = true;
        private static bool _showHeaderFilters = true;
        private static bool _showAdvancedSettings = false;

        internal static void Display(AlibabacloudOptions options)
        {
            _scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
            
            EditorGUILayout.LabelField("Network Tracking Configuration", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);

            // Enable Network Tracking toggle
            options.EnableNetworkTracking = EditorGUILayout.Toggle(
                new GUIContent("Enable Network Tracking", 
                    "Enable automatic network request tracking. When enabled, network requests will be automatically instrumented and tracked as RUM resources."),
                options.EnableNetworkTracking);

            EditorGUILayout.Space(10);

            GUI.enabled = options.Enabled && options.EnableNetworkTracking;

            // Sample Rate
            EditorGUILayout.LabelField("Sampling", EditorStyles.boldLabel);
            EditorGUILayout.Space(5);
            
            var sampleRate = EditorGUILayout.Slider(
                new GUIContent("Sample Rate", 
                    "Sample rate for network requests (0.0 to 1.0). 1.0 means all requests are tracked, 0.5 means 50% of requests are tracked."),
                (float)options.NetworkSampleRate, 0f, 1f);
            options.NetworkSampleRate = sampleRate;

            EditorGUILayout.Space(10);

            // URL Filters
            _showUrlFilters = EditorGUILayout.Foldout(_showUrlFilters, "URL Filters", true);
            if (_showUrlFilters)
            {
                EditorGUI.indentLevel++;
                EditorGUILayout.Space(5);
                
                // URL Allowlist
                EditorGUILayout.LabelField("URL Allowlist", EditorStyles.label);
                EditorGUILayout.HelpBox("If provided, only URLs containing these patterns will be tracked. Empty means all URLs are allowed (subject to blocklist).", MessageType.Info);
                options.NetworkUrlAllowlist = DrawStringArray(options.NetworkUrlAllowlist, "URL Pattern");
                
                EditorGUILayout.Space(5);
                
                // URL Blocklist
                EditorGUILayout.LabelField("URL Blocklist", EditorStyles.label);
                EditorGUILayout.HelpBox("URLs containing these patterns will not be tracked.", MessageType.Info);
                options.NetworkUrlBlocklist = DrawStringArray(options.NetworkUrlBlocklist, "URL Pattern");
                
                EditorGUI.indentLevel--;
            }

            EditorGUILayout.Space(10);

            // // Data Capture Settings -- todo 目前这块用不上
            // EditorGUILayout.LabelField("Data Capture", EditorStyles.boldLabel);
            // EditorGUILayout.Space(5);
            //
            // options.CaptureRequestBodySize = EditorGUILayout.ToggleLeft(
            //     new GUIContent("Capture Request Body Size", 
            //         "Whether to capture request body size in bytes."),
            //     options.CaptureRequestBodySize);
            //
            // options.CaptureResponseBodySize = EditorGUILayout.ToggleLeft(
            //     new GUIContent("Capture Response Body Size", 
            //         "Whether to capture response body size in bytes."),
            //     options.CaptureResponseBodySize);
            //
            // EditorGUILayout.Space(10);

            // Header Capture Settings
            _showHeaderFilters = EditorGUILayout.Foldout(_showHeaderFilters, "Header Capture", true);
            if (_showHeaderFilters)
            {
                EditorGUI.indentLevel++;
                EditorGUILayout.Space(5);
                
                options.CaptureRequestHeaders = EditorGUILayout.ToggleLeft(
                    new GUIContent("Capture Request Headers", 
                        "Whether to capture request headers. When enabled, request headers will be included in resource attributes."),
                    options.CaptureRequestHeaders);
                
                if (options.CaptureRequestHeaders)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.LabelField("Request Header Allowlist", EditorStyles.label);
                    EditorGUILayout.HelpBox("If empty, all headers are captured. If provided, only headers matching these names will be captured.", MessageType.Info);
                    options.NetworkRequestHeaderAllowlist = DrawStringArray(options.NetworkRequestHeaderAllowlist, "Header Name");
                    
                    EditorGUILayout.LabelField("Request Header Blocklist", EditorStyles.label);
                    EditorGUILayout.HelpBox("Headers matching these names will not be captured.", MessageType.Info);
                    options.NetworkRequestHeaderBlocklist = DrawStringArray(options.NetworkRequestHeaderBlocklist, "Header Name");
                    EditorGUI.indentLevel--;
                }
                
                EditorGUILayout.Space(5);
                
                options.CaptureResponseHeaders = EditorGUILayout.ToggleLeft(
                    new GUIContent("Capture Response Headers", 
                        "Whether to capture response headers. When enabled, response headers will be included in resource attributes."),
                    options.CaptureResponseHeaders);
                
                if (options.CaptureResponseHeaders)
                {
                    EditorGUI.indentLevel++;
                    EditorGUILayout.LabelField("Response Header Allowlist", EditorStyles.label);
                    EditorGUILayout.HelpBox("If empty, all headers are captured. If provided, only headers matching these names will be captured.", MessageType.Info);
                    options.NetworkResponseHeaderAllowlist = DrawStringArray(options.NetworkResponseHeaderAllowlist, "Header Name");
                    
                    EditorGUILayout.LabelField("Response Header Blocklist", EditorStyles.label);
                    EditorGUILayout.HelpBox("Headers matching these names will not be captured.", MessageType.Info);
                    options.NetworkResponseHeaderBlocklist = DrawStringArray(options.NetworkResponseHeaderBlocklist, "Header Name");
                    EditorGUI.indentLevel--;
                }
                
                EditorGUI.indentLevel--;
            }

            EditorGUILayout.Space(10);

            // Advanced Settings 
            _showAdvancedSettings = EditorGUILayout.Foldout(_showAdvancedSettings, "Advanced Settings", true);
            if (_showAdvancedSettings)
            {
                EditorGUI.indentLevel++;
                EditorGUILayout.Space(5);
                
                // HTTP Method Filter
                EditorGUILayout.LabelField("HTTP Method Filter", EditorStyles.label);
                EditorGUILayout.HelpBox("Select HTTP methods to track. If none are selected, all methods will be tracked.", MessageType.Info);
                
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                EditorGUILayout.BeginHorizontal();
                options.TrackHttpGet = EditorGUILayout.ToggleLeft("GET", options.TrackHttpGet, GUILayout.Width(80));
                options.TrackHttpPost = EditorGUILayout.ToggleLeft("POST", options.TrackHttpPost, GUILayout.Width(80));
                options.TrackHttpPut = EditorGUILayout.ToggleLeft("PUT", options.TrackHttpPut, GUILayout.Width(80));
                options.TrackHttpDelete = EditorGUILayout.ToggleLeft("DELETE", options.TrackHttpDelete, GUILayout.Width(100));
                EditorGUILayout.EndHorizontal();
                
                EditorGUILayout.BeginHorizontal();
                options.TrackHttpPatch = EditorGUILayout.ToggleLeft("PATCH", options.TrackHttpPatch, GUILayout.Width(80));
                options.TrackHttpHead = EditorGUILayout.ToggleLeft("HEAD", options.TrackHttpHead, GUILayout.Width(80));
                options.TrackHttpOptions = EditorGUILayout.ToggleLeft("OPTIONS", options.TrackHttpOptions, GUILayout.Width(100));
                EditorGUILayout.EndHorizontal();
                EditorGUILayout.EndVertical();
                
                EditorGUILayout.Space(5);
                
                // Status Code Ranges
                EditorGUILayout.LabelField("Status Code Ranges", EditorStyles.label);
                EditorGUILayout.HelpBox("If empty, all status codes are tracked. If provided, only requests with status codes in these ranges will be tracked. Format: \"200-299\", \"400-499\", etc.", MessageType.Info);
                options.NetworkStatusCodeRanges = DrawStringArray(options.NetworkStatusCodeRanges, "Status Code Range");
                
                EditorGUILayout.Space(5);
                
                // Trace Context
                EditorGUILayout.LabelField("Trace Context Propagation", EditorStyles.label);
                EditorGUILayout.HelpBox("Enable distributed tracing by injecting trace context headers into network requests. Each URL pattern can use W3C (traceparent) or SkyWalking (sw8) format.", MessageType.Info);
                
                options.EnableTraceContext = EditorGUILayout.Toggle(
                    new GUIContent("Enable Trace Context", 
                        "Enable trace context propagation for distributed tracing."),
                    options.EnableTraceContext);
                
                if (options.EnableTraceContext)
                {
                    EditorGUI.indentLevel++;
                    
                    EditorGUILayout.LabelField("Trace Context Configurations", EditorStyles.label);
                    EditorGUILayout.HelpBox("Configure URL patterns and their corresponding trace standards. Only URLs matching these patterns will have trace context injected.", MessageType.Info);
                    options.TraceContextConfigs = DrawTraceContextConfigArray(options.TraceContextConfigs);
                    
                    EditorGUI.indentLevel--;
                }
                
                EditorGUI.indentLevel--;
            }

            GUI.enabled = true;

            if (!options.EnableNetworkTracking && options.Enabled)
            {
                EditorGUILayout.Space(10);
                EditorGUILayout.HelpBox("Enable Network Tracking to configure network monitoring settings", MessageType.Info);
            }

            EditorGUILayout.EndScrollView();
        }

        private static string[] DrawStringArray(string[] array, string label)
        {
            if (array == null)
            {
                array = new string[0];
            }

            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField(label, EditorStyles.boldLabel);
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("+", GUILayout.Width(26)))
            {
                var newArray = new string[array.Length + 1];
                for (int i = 0; i < array.Length; i++)
                {
                    newArray[i] = array[i];
                }
                newArray[newArray.Length - 1] = string.Empty;
                array = newArray;
            }
            EditorGUILayout.EndHorizontal();

            if (array.Length == 0)
            {
                EditorGUILayout.HelpBox("No items. Click '+' to add.", MessageType.None);
                EditorGUILayout.EndVertical();
                return array;
            }

            int removeIndex = -1;
            for (int i = 0; i < array.Length; i++)
            {
                EditorGUILayout.BeginHorizontal();

                // Small index label, keep the text field as wide as possible
                GUILayout.Label($"{i}", GUILayout.Width(22));
                array[i] = EditorGUILayout.TextField(array[i] ?? string.Empty, GUILayout.ExpandWidth(true));

                if (GUILayout.Button("-", GUILayout.Width(26)))
                {
                    removeIndex = i;
                }

                EditorGUILayout.EndHorizontal();
            }

            if (removeIndex >= 0)
            {
                var newArray = new string[array.Length - 1];
                var dst = 0;
                for (int src = 0; src < array.Length; src++)
                {
                    if (src == removeIndex)
                    {
                        continue;
                    }

                    newArray[dst++] = array[src];
                }

                array = newArray;
            }

            EditorGUILayout.EndVertical();

            return array;
        }
        
        private static TraceContextConfig[] DrawTraceContextConfigArray(TraceContextConfig[] array)
        {
            if (array == null)
            {
                array = new TraceContextConfig[0];
            }

            EditorGUILayout.BeginVertical(EditorStyles.helpBox);
            
            EditorGUILayout.BeginHorizontal();
            EditorGUILayout.LabelField("Configurations", EditorStyles.boldLabel);
            GUILayout.FlexibleSpace();
            if (GUILayout.Button("+", GUILayout.Width(26)))
            {
                var newArray = new TraceContextConfig[array.Length + 1];
                for (int i = 0; i < array.Length; i++)
                {
                    newArray[i] = array[i];
                }
                newArray[newArray.Length - 1] = new TraceContextConfig();
                array = newArray;
            }
            EditorGUILayout.EndHorizontal();

            if (array.Length == 0)
            {
                EditorGUILayout.HelpBox("No trace context configurations. Click '+' to add.", MessageType.None);
                EditorGUILayout.EndVertical();
                return array;
            }

            int removeIndex = -1;
            for (int i = 0; i < array.Length; i++)
            {
                if (array[i] == null)
                {
                    array[i] = new TraceContextConfig();
                }
                
                EditorGUILayout.BeginVertical(EditorStyles.helpBox);
                
                EditorGUILayout.BeginHorizontal();
                EditorGUILayout.LabelField($"Config {i}", EditorStyles.boldLabel, GUILayout.Width(60));
                GUILayout.FlexibleSpace();
                if (GUILayout.Button("-", GUILayout.Width(26)))
                {
                    removeIndex = i;
                }
                EditorGUILayout.EndHorizontal();
                
                EditorGUI.indentLevel++;
                
                array[i].UrlPattern = EditorGUILayout.TextField(
                    new GUIContent("URL Pattern", 
                        "URL pattern to match (e.g., 'api.example.com', '/api/v1/')."),
                    array[i].UrlPattern ?? string.Empty);
                
                array[i].Standard = (TraceContextStandard)EditorGUILayout.EnumPopup(
                    new GUIContent("Trace Standard", 
                        "W3C uses traceparent header. SkyWalking uses sw8 header."),
                    array[i].Standard);
                
                EditorGUI.indentLevel--;
                
                EditorGUILayout.EndVertical();
            }

            if (removeIndex >= 0)
            {
                var newArray = new TraceContextConfig[array.Length - 1];
                var dst = 0;
                for (int src = 0; src < array.Length; src++)
                {
                    if (src == removeIndex)
                    {
                        continue;
                    }

                    newArray[dst++] = array[src];
                }

                array = newArray;
            }

            EditorGUILayout.EndVertical();

            return array;
        }
    }
}

