using System;
using RothenburgAR.Common;
using RothenburgAR.PointOfInterest;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;

namespace RothenburgAR.UI
{
    public class DetailsPanelBehaviour : MonoBehaviour
    {
        public TextMeshProUGUI DetailsText;
        public ScrollRect DetailsTextScrollRect;
        public DetailsModelBehaviour DetailsModel;

        private void Start()
        {
            gameObject.SetActive(false);
        }

        public bool HasModel
        {
            get { return _currentDisplayedModelGo != null; }
        }

        private GameObject _currentDisplayedModelGo;

        public void SetText(TextElement el)
        {
            SetText(el.GetTextByLanguage(LanguageManager.Instance.CurrentLanguageKey));
        }

        public void SetText(String el)
        {
            DetailsText.text = el;
            
            // Scroll to top
            DetailsTextScrollRect.normalizedPosition = new Vector2(0, 1);
        }

        public void SetModel(GameObject modelGo)
        {
            RemoveModel();
            modelGo.transform.SetParent(UIManager.Instance.UIObjectCamera.transform, false);
            modelGo.transform.localPosition += new Vector3(0, 0, 450);

            _currentDisplayedModelGo = modelGo;
            DetailsModel.CurrentModel = _currentDisplayedModelGo;

            DetailsModel.gameObject.SetActive(true);
        }

        public void SetModelFromPoi(PoiData data)
        {
            if (!data.HasModelDescription) return;
            try
            {
                SetModel(data.InstantiateModelPrefab());
            }
            catch (Exception)
            {
                // ignore, just do not display an object
                _currentDisplayedModelGo = null;
            }
        }
        
        public void RemoveModel()
        {
            DetailsModel.gameObject.SetActive(false);
            DetailsModel.CurrentModel = null;
            if (HasModel)
            {
                Destroy(_currentDisplayedModelGo);
                _currentDisplayedModelGo = null;
            }
        }

        public void UpdateOpeningAnimation(Vector3 position)
        {
            float duration = .4f;
            var scale = DisplayManager.Instance.GetComponent<RectTransform>().localScale.x;
            Vector3 screenMiddle = new Vector3(Screen.width / scale, Screen.height / scale, 0) * 0.5f;

            Vector3 startPos = Camera.main.WorldToScreenPoint(position) / scale - screenMiddle;
            Vector3 endPos = -screenMiddle + new Vector3(25, 25, 0);

            float startScale = 0.05f;
            float endScale = 1;

            var anim = GetComponent<Animation>();
            var clip = new AnimationClip
            {
                legacy = true,
                name = "DetailsOpen"
            };

            // inTangent and outTangent are the curve's angles to and from this keyframe in radians.
            // outTangent for all the first keyframe of all curves are set to directly point at the second frame,
            // effectively disabling the easing and making it a linear motion.
            // beware: setters for Keyframe.inTangent and Keyframe.outTangent seem to not work.
            var curvePosX = new AnimationCurve();
            curvePosX.AddKey(new Keyframe(0f, startPos.x, 0f, (endPos.x - startPos.x) / duration));
            curvePosX.AddKey(new Keyframe(duration, endPos.x));

            var curvePosY = new AnimationCurve();
            curvePosY.AddKey(new Keyframe(0f, startPos.y, 0f, (endPos.y - startPos.y) / duration));
            curvePosY.AddKey(new Keyframe(duration, endPos.y));

            clip.SetCurve(string.Empty, typeof(Transform), "localPosition.x", curvePosX);
            clip.SetCurve(string.Empty, typeof(Transform), "localPosition.y", curvePosY);

            var curveScaleX = new AnimationCurve();
            curveScaleX.AddKey(new Keyframe(0f, startScale, 0f, (endScale - startScale) / duration));
            curveScaleX.AddKey(new Keyframe(duration, endScale));

            var curveScaleY = new AnimationCurve();
            curveScaleY.AddKey(new Keyframe(0f, startScale, 0f, (endScale - startScale) / duration));
            curveScaleY.AddKey(new Keyframe(duration, endScale));

            clip.SetCurve(string.Empty, typeof(Transform), "localScale.x", curveScaleX);
            clip.SetCurve(string.Empty, typeof(Transform), "localScale.y", curveScaleY);

            anim.AddClip(clip, clip.name);
            anim.Play(clip.name);
        }

        public void OnDetailsPanelDrag(BaseEventData data)
        {
            DetailsModel.RotateModelByDrag(data as PointerEventData);
        }

        public void OnDetailsPanelPointerDown(BaseEventData data)
        {
            DetailsModel.BeginRotateModelByDrag(data as PointerEventData);
        }

        public void OnDetailsPanelEndDrag(BaseEventData data)
        {
            DetailsModel.EndRotateModelByDrag(data as PointerEventData);
        }

        private void OnDestroy()
        {
            RemoveModel();
        }
    }
}