﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Runtime.InteropServices;
using Alibabacloud.Rum.Unity.Logs;
using Alibabacloud.Rum.Unity.Network;
using Alibabacloud.Rum.Unity.Rum;
using Alibabacloud.Rum.Unity.Worker;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace Alibabacloud.Rum.Unity
{
    public class AlibabacloudSdk
    {
        public static readonly AlibabacloudSdk Instance = new();
        
        private IAlibabacloudPlatform _platform = new AlibabacloudNoOpPlatform();

        private AlibabacloudWorker _worker;
        // private IInternalLogger _internalLogger = new PassThroughInternalLogger();
        // private ResourceTrackingHelper _resourceTrackingHelper;
        private GameObject _performanceTrackerObject;
        private AlibabacloudUnityLogHandler _logHandler;
        
        public AlibabacloudOptions Options { get; private set; }
        
        /// <summary>
        // /// Initializes Alibabacloud Unity SDK while configuring the options.
        /// </summary>
        /// <param name="options">Callback to configure the options.</param>
        public static void InitWithPlatform(IAlibabacloudPlatform platform, AlibabacloudOptions options)
        {
            Instance.Init(platform, options);
        }

        /// <summary>
        /// Initializes Alibabacloud Unity SDK while providing an options object.
        /// </summary>
        /// <param name="options">The options object.</param>
        private void Init(IAlibabacloudPlatform platform, AlibabacloudOptions options)
        {
            _platform = platform;
            _worker = _platform.CreateWorker();
            Options = options;
       
            if (!options.Enabled)
            {
                return;
            }
      
            EnableRum(options);
            
            // todo 后面要加参数配置，是否开启
            _logHandler = new AlibabacloudUnityLogHandler(Rum);
            _logHandler.Attach();
            
            _worker.Start();
            
            // todo
            
        }
        /// <summary>
        /// The instance of the RUM feature of the Alibabacloud SDK. If RUM is not enabled,
        /// this property returns a NoOp implementation of the RUM interface, and will never return null.
        /// </summary>
        public IAlibabacloudRum Rum { get; private set; } = new AlibabacloudNoOpRum();

        private void EnableRum(AlibabacloudOptions options)
        {
            if (string.IsNullOrEmpty(options.ServiceId))
            {
                options.LogError("AppId is required");
            }
            
            // Prepare our interface to the platform-specific RUM API, and register it to handle worker messages in a
            // background thread
            var platformRum = _platform.InitRum(options);
            Rum = platformRum;
            _worker.AddProcessor(AlibabacloudRumProcessor.RumTargetName, new AlibabacloudRumProcessor(platformRum));
            
            // // Create our main-thread IAlibabacloudRum interface, which will enqueue messages for the worker-thread implementation
            // // to handle
            // var rumProxy = new AlibabacloudWorkerProxyRum(_worker);
            // Rum = rumProxy;
            
            // Track scene changes as RUM Views, if configured to do so
            if (options.AutomaticSceneTracking)
            {
                SceneManager.sceneLoaded += SceneManagerOnSceneLoaded;
                SceneManager.activeSceneChanged += SceneManagerOnActiveSceneChanged;
            }
        }
        
        private string _currentViewPath = null;
        private readonly Dictionary<string, long> _sceneLoadStartTimes = new Dictionary<string, long>();

        private void SceneManagerOnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            string scenePath = scene.path;
            long loadedTime = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            long loadTimeMs = 0;

            if (_sceneLoadStartTimes.TryGetValue(scenePath, out long startTime))
            {
                loadTimeMs = loadedTime - startTime;
                _sceneLoadStartTimes.Remove(scenePath);
            }
            
            Rum.StartView(scenePath, scene.name, new Dictionary<string, object>()
            {
                { "is_sub_scene", scene.isSubScene },
                { "is_loaded", scene.isLoaded },
                { "load_mode", "additive" },
                { "_alibabacloud.load_time", loadTimeMs }
            });
            
        }

        private void SceneManagerOnActiveSceneChanged(Scene previousScene, Scene nextScene)
        {
            // Record load start time when the scene transition begins
            string nextPath = nextScene.path;
            _sceneLoadStartTimes[nextPath] = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
            
            if (!string.IsNullOrEmpty(_currentViewPath) && _currentViewPath != nextPath)
            {
                Rum.StopView(_currentViewPath, new Dictionary<string, object>());
            }
            
            _currentViewPath = nextPath;
        }

        /// <summary>
        /// Shutdown the Alibabacloud SDK. Note, this method is primarily for internal use.
        /// </summary>
        public static void Shutdown()
        {
            Instance.ShutdownInstance();
        }
        
        
        private void ShutdownInstance()
        {
            // Always clean up SDK state
            _platform = null;
            _logHandler.Detach();
            _logHandler = null;
            _worker?.Stop();
            _worker = null;
            Options = null;
            
        }
    }
}