#if USE_VUPLEX_WEBVIEW
using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading.Tasks;

using TMPro;

using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

using Vuplex.WebView;
namespace XenseAR
{
    public class ARWorldWebview : MonoSingleton<ARWorldWebview>
    {
        public static event Action<ExternalInputEvent> OnWebViewInputted;
        private bool isWebViewShowOnApp = false;

        [SerializeField] AppSettingObject appSetting;
        [SerializeField] GameObject connectionError;
        [SerializeField] TextMeshProUGUI connectionErrorText;
        [SerializeField] Button reloadButton;

        public CanvasWebViewPrefab webViewPrefab;

        List<string> preventWebViewOverClick = new List<string>();

        public bool isWebViewReady = false;
        public bool isWebviewInitialized = false;
        public bool isWebviewError = false;

        public bool expectLocationPermissionChange = false;

        public string OnlineWebUrl;

        AMessageHandler messageHandler;

        private Action reloadButtonCallback;

        InternetConnectionChecker internetConnectionChecker;

        protected override void Awake()
        {
            // Grant Vuplex Webview permission prior to webview initialize
            // Check out https://support.vuplex.com/articles/webrtc
            Web.SetCameraAndMicrophoneEnabled(true);
#if UNITY_ANDROID && !UNITY_EDITOR
            AndroidWebView.SetCameraEnabled(true);
#endif

            DontDestroyOnLoad(this);
            base.Awake();

#if !UNITY_EDITOR && (UNITY_WEBPLAYER || UNITY_WEBGL)
            JavascriptMessageHandler.Instance.OnReceiveMessageWebGL.AddListener(ReceiveMessageWebGL);
#endif

            Container.Register(this);
            SceneManager.activeSceneChanged += OnActiveSceneChanged;
            messageHandler = new WebViewMessageHandlers();
#if !UNITY_WEBGL || UNITY_EDITOR
            LoadWebviewUrl(appSetting.XenseUrl.homeURL);
#endif
            internetConnectionChecker = gameObject.AddComponent<InternetConnectionChecker>();
            internetConnectionChecker.Init(OnlineWebUrl, OnConnected);
        }

        public async void LoadWebviewUrl(string inputUrl, bool reload = false)
        {
            string url = inputUrl;
            if (!string.IsNullOrEmpty(url))
            {
                if (url.Contains("?"))
                    url = url + "&app=1";
                else url = url + "?app=1";
                OnlineWebUrl = url;
                webViewPrefab.InitialUrl = LanguageSetting.InitLanguageSetting(url);
                if (reload)
                {
                    await webViewPrefab.WaitUntilInitialized();
                    //webViewPrefab.WebView.LoadUrl("https://vuplex.com");
                    webViewPrefab.WebView.LoadUrl(inputUrl);
                    Debug.Log("url" + url);
                }
            }
        }


        private async void OnApplicationPause(bool pause)
        {
            if (!pause)
            {
                if (expectLocationPermissionChange)
                {
                    expectLocationPermissionChange = false;
                    LocationPermissionController locationPermissionController = new LocationPermissionController();
                    if (await locationPermissionController.CheckPermission(false))
                        API.LocationPermissionGranted(true);
                }
            }
            PauseWebView(pause);
        }

        private async void OnApplicationFocus(bool focus)
        {
            if (focus && expectLocationPermissionChange)
            {
                expectLocationPermissionChange = false;
                LocationPermissionController locationPermissionController = new LocationPermissionController();
                if (await locationPermissionController.CheckPermission(false))
                    API.LocationPermissionGranted(true);
            }
        }

        private void OnEnable()
        {
#if UNITY_ANDROID && !UNITY_EDITOR
        if (webViewPrefab != null && webViewPrefab.WebView != null)
        {
            (webViewPrefab.WebView as AndroidWebView).Resume();
        }
        AndroidWebView.ResumeAll();
#endif
        }

        private async void Start()
        {
            reloadButton.onClick.AddListener(OnReloadClick);
#if !UNITY_WEBGL
            await webViewPrefab.WaitUntilInitialized();

            API.SendAPIMessage("webviewReady", "");
            isWebviewInitialized = true;

            webViewPrefab.WebView.LoadFailed += WebView_PageLoadFailed;
            webViewPrefab.WebView.MessageEmitted += Controls_MessageEmitted;

            webViewPrefab.WebView.SetDefaultBackgroundEnabled(false);

#if UNITY_IOS && !UNITY_EDITOR
        var iOSWebViewInstance = webViewPrefab.WebView as iOSWebView;
        iOSWebViewInstance.SetScrollViewBounces(false);
#endif
            try
            {
                await webViewPrefab.WebView.WaitForNextPageLoadToFinish();
            }
            catch (Exception ex) { }
            await Task.Delay(1000);
#endif
            API.Init(webViewPrefab);

            API.UpdateDeviceID(SystemInfo.deviceUniqueIdentifier);
            API.GetUid(appSetting.XenseUrl.authenticationUid);
        }

        protected override void OnDestroy()
        {
#if !UNITY_EDITOR && (UNITY_WEBPLAYER || UNITY_WEBGL)
        JavascriptMessageHandler.Instance.OnReceiveMessageWebGL.RemoveListener(ReceiveMessageWebGL);
#endif
            reloadButton.onClick.RemoveListener(OnReloadClick);
            messageHandler.OnDestroy();
#if !UNITY_WEBGL
            webViewPrefab.WebView.LoadFailed -= WebView_PageLoadFailed;
            webViewPrefab.WebView.MessageEmitted -= Controls_MessageEmitted;
#endif
            API.Clear();
            appSetting.LocationSetting.blockId = "";
            base.OnDestroy();
            SceneManager.activeSceneChanged -= OnActiveSceneChanged;
        }

        public void BackToPreviousPage()
        {
            isWebviewError = false;
            HideConnectionLostMessage();
        }

        #region Webview message

        void Controls_MessageEmitted(object sender, EventArgs<string> eventArgs)
        {
            if (preventWebViewOverClick.Contains(eventArgs.Value))
                return;
            Debug.Log(eventArgs.Value);

            preventWebViewOverClick.Add(eventArgs.Value);
            ReceivedWebviewMessage receivedWebviewMessage = JsonUtility.FromJson<ReceivedWebviewMessage>(eventArgs.Value);
            MessageProcessor.ProcessMessageAsync<string>(eventArgs.Value);
            RemovedEventArgs(eventArgs.Value);
        }

        private void RemovedEventArgs(string eventArg)
        {
            if (preventWebViewOverClick.Contains(eventArg))
            {
                preventWebViewOverClick.RemoveAll(messagePrevented => messagePrevented == eventArg);
            }
        }

        public void ReceiveMessageWebGL(string data)
        {
            MessageProcessor.ProcessMessageAsync<string>(data);
        }

        #endregion

        #region WebviewInput

        public void WebViewInputted(ExternalInputEvent ExternalInputData)
        {
            XenseARStandaloneInputModuleWrapper.SimulateExternalInput(ExternalInputData);
        }

        [Obsolete("Input listener script for webview have been moved to web native javascript. If no event is fired, check with your website provider/manager/mantainer")]
        private void AddWebInputListener()
        {
            AddAndExecuteListener(ExternalInputType.down);
        }

        [Obsolete("Input listener script for webview have been moved to web native javascript. If no event is fired, check with your website provider/manager/mantainer")]
        private void AddAndExecuteListener(string inputType)
        {
            webViewPrefab.WebView.PageLoadScripts.Add(webviewInputScript.Replace("{0}", inputType));
            //webViewPrefab.WebView.ExecuteJavaScript(webviewInputScript.Replace("{0}", inputType));
        }

        [Tooltip("Sample for website listener script")]
        string webviewInputScript = "document.body.addEventListener('{0}', (event) => {\n" +
#if !UNITY_EDITOR
                $"for (let i = 0; i < event.changedTouches.length; i++) {{\n" +
#endif
                        $"let elements = document.elementsFromPoint({ExternalInputData.clientX},{ExternalInputData.clientY});\n" +
                    "let notUICount = 0;\n" +

                    "elements.forEach((element) => {\n" +
                        "if (element.className.includes('not-ui')) {\n" +
                            "notUICount = notUICount + 1;\n" +
                        "}\n" +
                    "});\n" +

                    $"window.vuplex.postMessage('" +
                    "{" +
                        $"\"type\":\"webviewInput\"," +
                        $"\"message\":\"" +
                        "{" +
                            "\\\\\"type\\\\\":\\\\\"{0}\\\\\"," +
                            $"\\\\\"isOverWebviewUI\\\\\":'+(elements.length - notUICount > 2)+'," +
                            $"\\\\\"pointerId\\\\\":'+{ExternalInputData.id}+'," +
                            $"\\\\\"position\\\\\":" +
                            "{" +
                                $"\\\\\"x\\\\\":'+({ExternalInputData.clientX}/{ExternalInputData.viewPortWidth})+'," +
                                $"\\\\\"y\\\\\":'+(1 - {ExternalInputData.clientY}/{ExternalInputData.viewPortHeight})+'" +
                            "}," +
                            $"\\\\\"pressure\\\\\":'+{ExternalInputData.pressure}+'," +
                            $"\\\\\"tangentialPressure\\\\\":'+{ExternalInputData.tangentialPressure}+'," +
                            $"\\\\\"altitudeAngle\\\\\":'+{ExternalInputData.altitudeAngle}+'," +
                            $"\\\\\"azimuthAngle\\\\\":'+{ExternalInputData.azimuthAngle}+'," +
                            $"\\\\\"twist\\\\\":'+{ExternalInputData.twist}+'," +
                            $"\\\\\"tilt\\\\\":" +
                            "{" +
                                $"\\\\\"x\\\\\":'+{ExternalInputData.tiltX}+'," +
                                $"\\\\\"y\\\\\":'+{ExternalInputData.tiltY}+'" +
                            "}," +
                            $"\\\\\"radius\\\\\":" +
                            "{" +
                                $"\\\\\"x\\\\\":'+{ExternalInputData.radiusX}+'," +
                                $"\\\\\"y\\\\\":'+{ExternalInputData.radiusY}+'" +
                            "}" +
                        "}\"" +
                    "}');\n" +
#if !UNITY_EDITOR
                $"}}" +
#endif
                "});";

        #endregion

        #region Webview Connection
        private void WebView_PageLoadFailed(object sender, LoadFailedEventArgs e)
        {
            return;
            isWebviewError = true;
            connectionErrorText.text = Defines.UIText.webviewLoadFail +
                $"\r\n<size=14>Error: {e.NativeErrorCode}</size>" +
                $"\r\n<size=14>URL: {e.Url}</size>";
            if (SceneManager.GetActiveScene().name != "SplashScene")
            {
                ShowConnectionLostMessage();
            }
            if (webViewPrefab.WebView.Url == OnlineWebUrl)
            {
                internetConnectionChecker.StartCheck();
            }
        }

        private void OnActiveSceneChanged(Scene scene1, Scene scene2)
        {
            if (isWebviewError)
            {
                ShowConnectionLostMessage();
            }
        }

        public void ShowConnectionLostMessage(Action callback = null)
        {
            reloadButtonCallback = callback;
            Close();
            connectionError.SetActive(true);
        }

        public void HideConnectionLostMessage()
        {
            reloadButtonCallback = null;
            connectionError.SetActive(false);
        }

        private void OnConnected()
        {
            if (isWebviewError && webViewPrefab.WebView.Url == OnlineWebUrl)
                ReloadWebview();
        }

        public void OnReloadClick()
        {
            ReloadWebview();
        }

        private void ReloadWebview()
        {
            if (reloadButtonCallback != null)
                reloadButtonCallback.Invoke();
            else
                StartCoroutine(ReloadWebviewAsync());

            HideConnectionLostMessage();
        }

        private IEnumerator ReloadWebviewAsync()
        {
            isWebviewError = false;
            Open();
            if (SceneManager.GetActiveScene().name != "StartScene")
            {
                yield return SceneManager.UnloadSceneAsync(SceneManager.GetActiveScene(), UnloadSceneOptions.UnloadAllEmbeddedSceneObjects);
                Resources.UnloadUnusedAssets();
            }
            SceneManager.LoadScene("StartScene", LoadSceneMode.Single);

            webViewPrefab.WebView.LoadUrl(OnlineWebUrl);
        }

        #endregion

        #region Open and close webview

        public void CloseWebViewNavigation()
        {
            Close();
            EventManager.Instance.PostNotification(EVENT_TYPE.ClosevoucherWebViewPrefab, this);
        }

        public void ShowWebView()
        {
#if !UNITY_EDITOR && UNITY_WEBGL
            return;
#endif
            if (isWebviewError) return;
            var canvas = GetComponentInParent<Canvas>();
            RectTransform canvasRect = canvas.GetComponent<RectTransform>();
            RectTransform rectTransform = webViewPrefab.GetComponent<RectTransform>();

            Vector2 targetPosition = new Vector2(0f, canvasRect.sizeDelta.y);

            Vector2 targetSize = new Vector2(canvasRect.sizeDelta.x, canvasRect.sizeDelta.y);

            rectTransform.anchoredPosition = targetPosition;
            rectTransform.sizeDelta = targetSize;
        }

        public void HideWebView()
        {
            var canvas = GetComponentInParent<Canvas>();
            RectTransform canvasRect = canvas.GetComponent<RectTransform>();
            RectTransform rectTransform = webViewPrefab.GetComponent<RectTransform>();

            Vector2 targetSize = new Vector2(canvasRect.sizeDelta.x, canvasRect.sizeDelta.y);

            rectTransform.sizeDelta = targetSize;
            rectTransform.anchoredPosition = new Vector2(0f, -0.5f * canvasRect.sizeDelta.y);
            //rectTransform.anchoredPosition = Vector2.zero;
        }

        public void Open()
        {
            // call show webview
            ShowWebView();
            isWebViewShowOnApp = true;
        }

        public void Close()
        {
            // call hide webview
            HideWebView();
            isWebViewShowOnApp = false;
        }

        private void PauseWebView(bool pauseStatus)
        {
            if (!isWebViewShowOnApp) return;
            
            if (pauseStatus)
            {
                HideWebView(); 
            }
            else
            {
                ShowWebView();
            }
        }

        #endregion
    }
}
#endif