using System;
using Alibabacloud.Rum.Unity.Rum;
using Alibabacloud.Rum.Unity.Worker;
using Alibabacloud.Rum.Unity;
using Alibabacloud.Rum.Unity.Logs;
using Alibabacloud.Rum.Unity.Network;
using UnityEngine;
using UnityEngine.Scripting;
using Logger = Alibabacloud.Rum.Unity.Logs.Logger;

[assembly: UnityEngine.Scripting.Preserve]
[assembly: UnityEngine.Scripting.AlwaysLinkAssembly]

namespace Alibabacloud.Rum.Unity.Android
{
    [Preserve]
    public static class AlibabacloudInitialization
    {
        [RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
        public static void InitializeAlibabacloud()
        {
            var options = AlibabacloudOptions.LoadAlibabacloudUnityOptions();
            if (options != null && options.Enabled)
            {
                var androidPlatform = new AndroidPlatform();
                androidPlatform.Init(options);
                AlibabacloudSdk.InitWithPlatform(androidPlatform, options);
            }
        }
    }
        
    public class AndroidPlatform : IAlibabacloudPlatform
    {    
        private AndroidJavaClass _alibabacloudClass;
        private const string RumClassName = "com.alibabacloud.rum.android.sdk.AlibabaCloudRum";
    
        public AndroidPlatform()
        {
            try
            {
                _alibabacloudClass = new AndroidJavaClass(RumClassName);
            }
            catch (Exception)
            {
                _alibabacloudClass = null;
            }
        }
        public IAlibabacloudRum InitRum(AlibabacloudOptions options)
        {
            return new AndroidRum(_alibabacloudClass, options);
        }
            
        public void Init(AlibabacloudOptions options)
        {
    
            if (_alibabacloudClass == null)
            {
                options.LogError("Initialization aborted: RUM class not initialized");
                return;
            }
    
            try
            {
                // All setter methods return void, not a builder pattern
                // Call setServiceId first
                _alibabacloudClass.CallStatic("setServiceId", options.ServiceId);
    
                // Call setDebuggable if enabled
                if (options.EnableNativeSDKLogDebug)
                {
                    _alibabacloudClass.CallStatic("setDebuggable", options.EnableNativeSDKLogDebug);
                }
    
                // Call setWorkspace if provided
                if (!string.IsNullOrEmpty(options.Workspace))
                {
                    _alibabacloudClass.CallStatic("setWorkspace", options.Workspace);
                }
                    
                // Call setAppType
                _alibabacloudClass.CallStatic("setAppType", AlibabacloudCommonParam.ScreenType);
    
                // Call start(endpoint, serviceId)
                _alibabacloudClass.CallStatic("start", options.Endpoint, options.ServiceId);
            }
            catch (Exception)
            {
                // Silently ignore JNI errors
            }
        }
        

        public AlibabacloudWorker CreateWorker()
        {
            return new ThreadedWorker();
        }
        
        /// <summary>
        /// Get native stack trace from IL2CPP for Android NDK format.
        /// This converts C# exception stack frames to Android native (NDK) stack trace format.
        /// </summary>
        /// <param name="error">The C# exception to convert.</param>
        /// <returns>Native stack trace in Android NDK format, or null if conversion fails or is not enabled.</returns>
        public string GetNativeStack(Exception error)
        {
            // Don't perform this action if not instructed to translate stacks
            if (error == null)
            {
                return null;
            }

            string resultStack = null;
            try
            {
                if (Il2CppErrorHelper.GetNativeStackFrames(
                        error,
                        out IntPtr[] frames,
                        out string imageUuid,
                        out string imageName))
                {
                    if (string.IsNullOrEmpty(imageName))
                    {
                        // Sometimes, Unity returns nothing in the imageName, sometimes it returns the name with
                        // an extra letter. We'll use the default libil2cpp.so name.
                        imageName = "libil2cpp.so";
                    }

                    // imageName sometimes comes back with an extra letter or symbol at the end (Unity bug)
                    if (!imageName.EndsWith(".so"))
                    {
                        // Strip off everything after .so
                        var soIndex = imageName.IndexOf(".so", StringComparison.Ordinal);
                        if (soIndex > 0)
                        {
                            imageName = imageName.Substring(0, soIndex + 3);
                        }
                    }

                    // Format of Android Native (NDK) stack trace:
                    // <frame number>  pc <address_offset>  <library_name>
                    // Example:
                    //   #00 pc 00012345  libil2cpp.so
                    //   #01 pc 00023456  libil2cpp.so
                    var stackBuilder = new System.Text.StringBuilder();
                    for (int i = 0; i < frames.Length; ++i)
                    {
                        var frame = frames[i].ToInt64();

                        // Format frame number with leading zero for consistency
                        // Currently assuming the frames are all relative addresses
                        stackBuilder.AppendLine($"#{i:D2} pc {frame:x8}  {imageName}");
                    }

                    resultStack = stackBuilder.ToString();
                }
            }
            catch (Exception)
            {
                // Silently ignore native stack extraction errors
            }

            return resultStack;
        }

    }
}


