using System;
using System.Collections.Generic;
using System.Text;
using Alibabacloud.Rum.Unity.Logs;
using Alibabacloud.Rum.Unity.Network;
using Alibabacloud.Rum.Unity.Rum;
using UnityEngine;

namespace Alibabacloud.Rum.Unity.Windows
{
    /// <summary>
    /// Windows implementation of IAlibabacloudRum using native SDK
    /// </summary>
    public class WindowsRum : IAlibabacloudRum
    {
        private readonly AlibabacloudOptions _options;
        private string _currentViewId;
        private string _currentViewName;

        public WindowsRum(AlibabacloudOptions options)
        {
            _options = options;
        }

        // Skip native invocations when the alibabacloud_rum.dll could not be loaded.
        // This prevents every public API from spamming DllNotFoundException stacks
        // when the SDK is effectively disabled.
        private static bool IsNativeReady => WindowsDllLoader.IsAvailable;

        public void ReportException(Exception ex)
        {
            if (ex == null || !IsNativeReady)
            {
                return;
            }

            try
            {
                IntPtr exceptionPtr = AlibabacloudRumNativeBridge.alibabacloud_rum_custom_exception_new(
                    ex.GetType().Name ?? "Exception",
                    ex.Message ?? "No message");

                if (exceptionPtr == IntPtr.Zero)
                {
                    _options?.LogError("[ALIBABACLOUD Windows] Failed to create exception object");
                    return;
                }

                // Set stack trace
                if (!string.IsNullOrEmpty(ex.StackTrace))
                {
                    AlibabacloudRumNativeBridge.alibabacloud_rum_custom_exception_set_stack(
                        exceptionPtr, ex.StackTrace);
                }

                // Set source
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_exception_set_source(
                    exceptionPtr, "unity");

                // Set caused by
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_exception_set_caused_by(
                    exceptionPtr, "unity");

                // Report the exception
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_exception_report(exceptionPtr);

                // NOTE: Do NOT call alibabacloud_rum_custom_exception_free here.
                // After *_report the native SDK takes ownership of the object
                // (it may be queued for async dispatch). Freeing it again would be
                // a double-free and crashes the process.
            }
            catch (Exception e)
            {
                _options?.LogError("[ALIBABACLOUD Windows] ReportException failed: {0}\n{1}", 
                    e.Message, e.StackTrace);
            }
        }

        public void ReportResource(string type,
            string url,
            string method,
            int statusCode,
            string errorMessage,
            bool success,
            TraceContext traceContext,
            Measuring measuring)
        {
            if (!IsNativeReady) return;
            try
            {
                IntPtr resourcePtr = AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_new(
                    url ?? string.Empty,
                    method ?? "GET");

                if (resourcePtr == IntPtr.Zero)
                {
                    _options?.LogError("[ALIBABACLOUD Windows] Failed to create resource object");
                    return;
                }

                // Set resource type
                int resourceType = GetResourceType(type);
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_type(resourcePtr, resourceType);

                // Set status code
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_status_code(
                    resourcePtr, statusCode);

                // Set success
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_success(
                    resourcePtr, success ? 1 : 0);

                // Set error message
                if (!success && !string.IsNullOrEmpty(errorMessage))
                {
                    AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_error_message(
                        resourcePtr, errorMessage);
                }

                // Set measuring metrics
                if (measuring != null)
                {
                    AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_measuring(
                        resourcePtr,
                        measuring.Duration,
                        measuring.Size,
                        0, // connect_duration
                        0, // ssl_duration
                        0, // dns_duration
                        0, // redirect_duration
                        0, // first_byte_duration
                        0  // download_duration
                    );
                }

                // Set trace context
                if (traceContext != null)
                {
                    if (!string.IsNullOrEmpty(traceContext.TraceId))
                    {
                        AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_trace_id(
                            resourcePtr, traceContext.TraceId);
                    }
                    if (!string.IsNullOrEmpty(traceContext.SpanId))
                    {
                        AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_span_id(
                            resourcePtr, traceContext.SpanId);
                    }

                    // // Set tracing protocol todo 目前pc sdk应该没有这个接口，链路打通可以再看下如何处理
                    // int protocol = traceContext.Protocol == TraceContextStandard.SkyWalking 
                    //     ? (int)AlibabacloudRumTracingProtocol.SkyWalking 
                    //     : (int)AlibabacloudRumTracingProtocol.W3C;
                    // AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_set_protocol(
                    //     resourcePtr, protocol);
                }

                // Report the resource
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_resource_report(resourcePtr);

                // NOTE: Do NOT call alibabacloud_rum_custom_resource_free here. See comment in ReportException.
            }
            catch (Exception e)
            {
                _options?.LogError("[ALIBABACLOUD Windows] ReportResource failed: {0}\n{1}", 
                    e.Message, e.StackTrace);
            }
        }

        public void ReportEvent(string eventName, string group, double value,
            Dictionary<string, object> info)
        {
            if (!IsNativeReady) return;
            try
            {
                IntPtr eventPtr = AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_new(
                    "custom",
                    eventName ?? string.Empty);

                if (eventPtr == IntPtr.Zero)
                {
                    _options?.LogError("[ALIBABACLOUD Windows] Failed to create event object");
                    return;
                }

                // Set value
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_set_value(eventPtr, value);

                // Set group
                if (!string.IsNullOrEmpty(group))
                {
                    AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_set_group(eventPtr, group);
                }

                // Add extra info
                if (info != null)
                {
                    foreach (var kv in info)
                    {
                        string valueStr = kv.Value?.ToString() ?? string.Empty;
                        AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_add_extra(
                            eventPtr, kv.Key, valueStr);
                    }
                }

                // Report the event
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_report(eventPtr);

                // NOTE: Do NOT call alibabacloud_rum_custom_event_free here. See comment in ReportException.
            }
            catch (Exception e)
            {
                _options?.LogError("[ALIBABACLOUD Windows] ReportEvent failed: {0}\n{1}", 
                    e.Message, e.StackTrace);
            }
        }

        public void ReportLog(string logContent, string logName, string logLevel, string stackTrace,
            Dictionary<string, object> extraInfo)
        {
            if (!IsNativeReady) return;
            try
            {
                IntPtr logPtr = AlibabacloudRumNativeBridge.alibabacloud_rum_custom_log_new(
                    "unity",
                    logName ?? "unity");

                if (logPtr == IntPtr.Zero)
                {
                    _options?.LogError("[ALIBABACLOUD Windows] Failed to create log object");
                    return;
                }

                // Set log level
                int level = GetLogLevel(logLevel);
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_log_set_log(
                    logPtr, level, logContent ?? string.Empty);

                // Add stack trace as extra
                if (!string.IsNullOrEmpty(stackTrace))
                {
                    AlibabacloudRumNativeBridge.alibabacloud_rum_custom_log_add_extra(
                        logPtr, "stack_trace", stackTrace);
                }

                // Add extra info
                if (extraInfo != null)
                {
                    foreach (var kv in extraInfo)
                    {
                        string valueStr = kv.Value?.ToString() ?? string.Empty;
                        AlibabacloudRumNativeBridge.alibabacloud_rum_custom_log_add_extra(
                            logPtr, kv.Key, valueStr);
                    }
                }

                // Report the log
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_log_report(logPtr);

                // NOTE: Do NOT call alibabacloud_rum_custom_log_free here. See comment in ReportException.
            }
            catch (Exception e)
            {
                _options?.LogError("[ALIBABACLOUD Windows] ReportLog failed: {0}\n{1}", 
                    e.Message, e.StackTrace);
            }
        }

        public void StartView(string key, string name, Dictionary<string, object> attributes)
        {
            if (!IsNativeReady) return;
            try
            {
                string viewName = !string.IsNullOrEmpty(name) ? name : key;
                
                // Generate 32-character hexadecimal random viewId
                string viewId = GenerateViewId();
                
                // Update global view state
                _currentViewId = viewId;
                _currentViewName = viewName;

                IntPtr eventPtr = AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_new(
                    "view",
                    viewName ?? string.Empty);

                if (eventPtr == IntPtr.Zero)
                {
                    _options?.LogError("[ALIBABACLOUD Windows] Failed to create view event object");
                    return;
                }

                // Add view attributes
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_add_extra(
                    eventPtr, "view_id", viewId);
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_add_extra(
                    eventPtr, "view_key", key ?? string.Empty);
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_add_extra(
                    eventPtr, "view_type", "unity");

                // Add custom attributes
                if (attributes != null)
                {
                    foreach (var kv in attributes)
                    {
                        string valueStr = kv.Value?.ToString() ?? string.Empty;
                        AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_add_extra(
                            eventPtr, kv.Key, valueStr);
                    }
                }

                // Report the view event
                AlibabacloudRumNativeBridge.alibabacloud_rum_custom_event_report(eventPtr);

                // NOTE: Do NOT call alibabacloud_rum_custom_event_free here. See comment in ReportException.
                // Calling free after report caused a hard crash on Windows Standalone
                // (event_free internally accesses memory already released by the SDK).
            }
            catch (Exception e)
            {
                _options?.LogError("[ALIBABACLOUD Windows] StartView failed: {0}\n{1}", 
                    e.Message, e.StackTrace);
            }
        }

        public void StopView(string key, Dictionary<string, object> attributes)
        {
            // View tracking is handled by StartView - next StartView will end the previous view
            // We keep the current view state for any pending events
        }

        #region Helper Methods

        private static int GetLogLevel(string level)
        {
            return level?.ToLower() switch
            {
                "trace" => (int)AlibabacloudRumLogLevel.Trace,
                "debug" => (int)AlibabacloudRumLogLevel.Debug,
                "info" => (int)AlibabacloudRumLogLevel.Info,
                "warn" => (int)AlibabacloudRumLogLevel.Warn,
                "error" => (int)AlibabacloudRumLogLevel.Error,
                "fatal" => (int)AlibabacloudRumLogLevel.Fatal,
                _ => (int)AlibabacloudRumLogLevel.Info
            };
        }

        private static int GetResourceType(string type)
        {
            return type?.ToLower() switch
            {
                "document" => (int)AlibabacloudRumResourceType.Document,
                "xhr" => (int)AlibabacloudRumResourceType.Xhr,
                "fetch" => (int)AlibabacloudRumResourceType.Fetch,
                "beacon" => (int)AlibabacloudRumResourceType.Beacon,
                "css" => (int)AlibabacloudRumResourceType.Css,
                "js" => (int)AlibabacloudRumResourceType.Js,
                "image" => (int)AlibabacloudRumResourceType.Image,
                "font" => (int)AlibabacloudRumResourceType.Font,
                "media" => (int)AlibabacloudRumResourceType.Media,
                _ => (int)AlibabacloudRumResourceType.Other
            };
        }

        private static string GenerateViewId()
        {
            var sb = new StringBuilder(32);
            var random = new System.Random();
            const string hexChars = "0123456789abcdef";

            for (int i = 0; i < 32; i++)
            {
                sb.Append(hexChars[random.Next(hexChars.Length)]);
            }

            return sb.ToString();
        }

        #endregion
    }
}
