using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using UnityEngine;
using UnityEngine.SceneManagement;
using LitJson;
using System;
using DG.Tweening;

// Version: 1.1.2

namespace FVS
{
    public class FVSUnityReact : MonoSingleton<FVSUnityReact>
    {
        [DllImport("__Internal")]
        private static extern void ReactCallback(string componentId, string type, string outParams);

        // 用来判断方法是否可用
        private static bool _isReactCallbackAvailable = false;
        
        /// <summary>
        /// 安全调用 ReactCallback（自动判断 JS 方法是否存在）
        /// </summary>
        public static void SafeReactCallback(string componentId, string type, string outParams)
        {
            // 只判断一次，缓存结果
            if (!_isReactCallbackAvailable)
            {
                try
                {
                    // 调用一个空内容，测试是否存在
                    ReactCallback("", "", "");
                    _isReactCallbackAvailable = true;
                }
                catch
                {
                    _isReactCallbackAvailable = false;
                }
            }

            if (_isReactCallbackAvailable)
            {
                ReactCallback(componentId, type, outParams);
            }
        }

        private string ReactComponentId;

        [LocalizedHeader("Header_SceneConfigJson")]
        [TextArea(5, 10)]
        public string jsonConfig;

        [LocalizedHeader("Header_UnityEventList")]
        public FVSUnityEvent[] events = new FVSUnityEvent[0];

        [LocalizedHeader("Header_UnityActionList")]
        public FVSUnityAction[] actions = new FVSUnityAction[0];

        [LocalizedHeader("Header_SceneManagement")]
        public FVSSceneConfig sceneConfig;

        private void Log(string info)
        {
            string id = "undefined ReactComponentId";
            if (ReactComponentId != null && ReactComponentId != "")
            {
                id = ReactComponentId;
            }
            Scene activeScene = SceneManager.GetActiveScene();
            Debug.Log(id + ": " + activeScene.name + ": " + info);
        }

        void OnEnable()
        {
            Log("FVSMain OnEnable");
        }

        void OnDisable()
        {
            Log("FVSMain OnDisable");
        }

        /// <summary>
        /// 初始化 FVSUnityReact, 建立通信
        /// </summary>
        /// <param name="id"></param>
        public void InitReactComponent(string id)
        {
#if UNITY_WEBGL && !UNITY_EDITOR
    WebGLInput.captureAllKeyboardInput = false;
#endif
            ReactComponentId = id;
            Log("InitReact");

            if (CheckReady())
            {
                GetUnityJsonConfig();
            }
        }

        public void GetUnityJsonConfig()
        {
            Log("SetUnityConfig");
            SendMessageToReact(MessageType.SetUnityConfig, jsonConfig);
        }

        private bool CheckReady()
        {
            return CheckReactComponentIdReady() && CheckSceneReady() && CheckJsonConfigReady() && CheckGameObjectsReady();
        }

        private bool CheckReactComponentIdReady()
        {
            if (ReactComponentId == null || ReactComponentId == "")
            {
                Log("ReactComponentId is not ready");
                return false;
            }
            Log("ReactComponentId is ready");
            return true;
        }

        private bool CheckSceneReady()
        {
            Scene activeScene = SceneManager.GetActiveScene();
            if (activeScene == null || !activeScene.isLoaded)
            {
                Log("Scene is not ready");
                return false;
            }
            Log("Scene is ready");
            return true;
        }

        private bool CheckJsonConfigReady()
        {
            if (jsonConfig == null || jsonConfig == "")
            {
                Log("Config json is not ready");
                return false;
            }
            Log("Config json is ready");
            return true;
        }

        private bool CheckGameObjectsReady()
        {
            if (!CheckJsonConfigReady())
            {
                return false;
            }

            JsonData configs = JsonMapper.ToObject(jsonConfig);
            ICollection<string> types = configs.Keys;
            foreach (string type in types)
            {
                JsonData config = configs[type];
                if (config == null || !config.ContainsKey("value"))
                {
                    continue;
                }

                JsonData value = config["value"];

                if (value == null || !value.IsArray)
                {
                    continue;
                }

                foreach (JsonData item in value)
                {
                    if (item == null || !item.ContainsKey("gameObject"))
                    {
                        continue;
                    }

                    JsonData gameObjectName = item["gameObject"];

                    if (gameObjectName.IsString)
                    {
                        if (GameObject.Find((string)gameObjectName) == null)
                        {
                            Log("GameObject is not ready: " + gameObjectName);
                            return false;
                        } else
                        {
                            Log("GameObject is ready: " + gameObjectName);
                        }
                    }
                }
            }

            return true;

        }

        /// <summary>
        /// 设置相机状态
        /// </summary>
        /// <param name="data"></param>
        public void SetCameraState(string data)
        {
            Log(data);
            CameraState state = JsonMapper.ToObject<CameraState>(data);
            Camera camera = Camera.main;
            camera.transform.DOMove(BaseUtils.ParseVector3(state.position), 2);
            camera.transform.DORotate(BaseUtils.ParseVector3(state.rotation), 2);
        }

        /// <summary>
        /// 获取相机状态
        /// </summary>
        public void GetCameraState()
        {
            Camera camera = Camera.main;
            if (camera == null) {
                Log("GetCameraState: Camera not found: main camera");
                return;
            }
            JsonWriter jw = new JsonWriter();
            jw.WriteObjectStart();
            jw.WritePropertyName("position");

            BaseUtils.WriteVector3(jw, camera.transform.position);

            jw.WritePropertyName("rotation");
            BaseUtils.WriteVector3(jw, camera.transform.eulerAngles);

            jw.WriteObjectEnd();

            Log(jw.ToString());

            SendMessageToReact(MessageType.UpdateCameraState, jw.ToString());
        }

        public void SwitchScene(string name)
        {
            Scene activeScene = SceneManager.GetActiveScene();
            if (name == activeScene.name)
            {
                SendMessageToReact(MessageType.LoadScene, $"{{\"name\":\"{name}\",\"progress\": 1.0}}");
                return;
            }

            GameObject gameObject = GameObject.Find("FVSMain");
 
            int index = 0;
            for (int i = 0, len = sceneConfig.scenes.Length; i < len; i++)
            {
                if (name == sceneConfig.scenes[i].name)
                {
                    index = i;
                    break;
                }
            }

            Log("LoadScene: " + name);
            StartCoroutine(LoadAsyncScene(name, index));

            if (gameObject != null)
            {
                gameObject.SetActive(false);
            }
        }

        private IEnumerator LoadAsyncScene(string sceneName, int sceneBuildIndex)
        {
            AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(sceneBuildIndex);

            while (!asyncLoad.isDone)
            {
                float progress = asyncLoad.progress;
                if (progress >= 0.9f) {
                    progress = 1.0f;
                }
                SendMessageToReact(MessageType.LoadScene, $"{{\"name\":\"{sceneName}\",\"progress\":{progress}}}");

                yield return null;
            }
        }

        public void SetCameraZoomObserverStateForClickable(int enabled)
        {
            bool isEnabled = enabled == 1 ? true : false;
            FVSClickable.zoomObserverEnabled = isEnabled;
        }
        
        /// <summary>
        /// 传递Unity事件
        /// </summary>
        /// <param name="eventName"></param>
        /// <param name="data"></param>
        public void SendUnityEvent(string eventName, string data = "")
        {
            foreach (FVSUnityEvent unityEvent in events)
            {
                if (unityEvent.name == eventName)
                {
                    JsonWriter jw = new JsonWriter();
                    jw.WriteArrayStart();
                    jw.Write(eventName);
                    jw.Write(data);
                    jw.WriteArrayEnd();

                    SendMessageToReact(MessageType.TriggerUnityEvent, jw.ToString());
                }
            }
        }


        /// <summary>
        /// Unity 与 React通信.
        /// </summary>
        /// <param name="type"></param>
        /// <param name="data"></param>
        public void SendMessageToReact(MessageType type, string data = "")
        {
#if UNITY_WEBGL && !UNITY_EDITOR
            SafeReactCallback(ReactComponentId, type.ToString(), data);
            if (!_isReactCallbackAvailable) {
                Log("ReactCallback is undefined");
                Log(type.ToString() + ":" + data);
                return;
            }

#else
            Log(type.ToString() + ":" + data);
#endif

        }

        public void FireMouseOver()
        {
            this.SendMessageToReact(MessageType.MouseOver);
        }

        public void FireMouseExit()
        {
            this.SendMessageToReact(MessageType.MouseExit);
        }

    }

    public enum MessageType
    {
        TriggerUnityEvent,
        SetUnityConfig,
        UpdateCameraState,
        MouseOver,
        MouseExit,
        UpdateClickableScreenPos,
        LoadScene
    }

    struct CameraState
    {
        public float[] position;
        public float[] rotation;
    }

    [Serializable]
    public struct FVSUnityAction
    {
        [LocalizedHeader("Header_ActionName")]
        public string name;
        [LocalizedHeader("Header_ActionDisplayName")]
        public string displayName;
    }

    [Serializable]
    public struct FVSUnityEvent
    {
        [LocalizedHeader("Header_EventName")]
        public string name;
        [LocalizedHeader("Header_EventDisplayName")]
        public string displayName;
        [LocalizedHeader("Header_ParameterList")]
        public FVSUnityEventParameter[] parameters;
    }

    [Serializable]
    public struct FVSUnityEventParameter
    {
        [LocalizedHeader("Header_ParameterKey")]
        public string key;
        [LocalizedHeader("Header_ParameterDisplayName")]
        public string displayName;
    }

    [Serializable]
    public struct FVSSceneConfig
    {
        [LocalizedHeader("Header_CurrentScene")]
        public string current;

        [LocalizedHeader("Header_SceneList")]
        public FVSSceneItem[] scenes;
    }

    [Serializable]
    public struct FVSSceneItem
    {
        [LocalizedHeader("Header_SceneName")]
        public string name;
        [LocalizedHeader("Header_SceneDisplayName")]
        public string displayName;
    }
}

