using UnityEngine;
using RothenburgAR.PointOfInterest;
using System.Collections;
using System;
using UnityEngine.EventSystems;
using System.Linq;

namespace RothenburgAR.UI
{
    public class FullscreenModelViewBehaviour : BaseViewBehaviour
    {
        public DetailsModelBehaviour DetailsModel;
        public GameObject IconLoading;
        public GameObject Icon3D;

        private GameObject _currentDisplayedModelGo;
        private PoiData currentPoiData;

        public new void SwitchToARView()
        {
            UIManager.Instance.SwitchToView(ViewName.ARView);
            var arViewBehaviour = UIManager.Instance.ARViewBehaviour;
            
            // Find poi and corresponding tracker
            var trackables = Vuforia.TrackerManager.Instance.GetStateManager().GetTrackableBehaviours().ToList();
            PoiBehaviour poiBehaviour = null;
            Vuforia.TrackableBehaviour trackable = null;
            foreach (var t in trackables)
            {
                var pois = t.GetComponentsInChildren<PoiBehaviour>().ToList();
                if (pois.Count == 0) continue;

                poiBehaviour = pois.FirstOrDefault(p => p.ReferencedID == currentPoiData.ID);
                if (poiBehaviour != null)
                {
                    trackable = t;
                    break;
                }
            }

            // Display Poi Details if poi was found
            if (poiBehaviour == null) return;
            arViewBehaviour.DisplayPoiDetails(poiBehaviour, false);

            // Disable Projection Effect if poi is not currently in view
            if (trackable.CurrentStatus != Vuforia.TrackableBehaviour.Status.TRACKED)
            {
                arViewBehaviour.ProjectionEffect.gameObject.SetActive(false);
            }
        }

        public void SetModelFromPoi(PoiData data)
        {
            if (!data.HasModelDescription) return;

            this.currentPoiData = data;
            StartCoroutine(SetModelCoroutine(data));
        }

        public IEnumerator SetModelCoroutine(PoiData data)
        {
            if (!data.IsModelLoaded)
            {
                StartCoroutine(data.LoadModel());

                DetailsModel.gameObject.SetActive(true);
                Icon3D.SetActive(true);
                IconLoading.SetActive(true);

                yield return new WaitUntil(() => data.IsModelLoaded || data.ModelLoadFailed);
            }

            if (data.ModelLoadFailed)
            {
                //TODO display error message to user
                RemoveModel();
                yield break;
            }

            SetModel(data.InstantiateModelPrefab());
        }

        private void SetModel(GameObject modelGo)
        {
            modelGo.transform.SetParent(UIManager.Instance.UIObjectCamera.transform, false);

            var meshFilter = modelGo.GetComponentInChildren<MeshFilter>();
            if (meshFilter == null) throw new Exception("No MeshFilter in Object!");

            var mesh = meshFilter.mesh;
            if (mesh == null) throw new Exception("No Mesh in Model!");

            //TODO remove when metadata model rotation is no longer a thing
            mesh.RecalculateBounds();

            var scale = 1f / Mathf.Max(mesh.bounds.size.x, mesh.bounds.size.y, mesh.bounds.size.z);
            modelGo.transform.localScale = new Vector3(scale, scale, scale);
            var pos = -mesh.bounds.center * scale;
            pos += new Vector3(0, 0, -modelGo.transform.localPosition.z + 2f);
            modelGo.transform.localPosition = pos;

            _currentDisplayedModelGo = modelGo;
            DetailsModel.CurrentModel = _currentDisplayedModelGo;

            DetailsModel.gameObject.SetActive(true);
            Icon3D.SetActive(false);
            IconLoading.SetActive(false);
        }

        private void RemoveModel()
        {
            DetailsModel.gameObject.SetActive(false);
            DetailsModel.CurrentModel = null;

            if (_currentDisplayedModelGo != null)
            {
                Destroy(_currentDisplayedModelGo);
                _currentDisplayedModelGo = null;
                Icon3D.SetActive(false);
                IconLoading.SetActive(false);
            }
        }

        private void OnDestroy()
        {
            RemoveModel();
        }

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

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

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