using UnityEngine;
#if UNITY_EDITOR
using UnityEditor;
#endif
using System.Collections.Generic;
using System;
using System.IO;

namespace Thousandto.Cinematic
{
    //剧情对象
    [Serializable]
    public class CinematicObj : ICinematic
    {
        public int EventType = 0;
        public List<CinematicKeyframe> KeyframeList;
        public string Name;
        public int CurFrame = -1;

        //帧率
        public int FrameRate = 30;
        public bool IsCamera;
        public int CameraDepth = 10;
        public int LayMask = 1;
        public bool IsFollowCamera = false;

        [NonSerialized]
        public Vector3[] PathV3Array;
        [NonSerialized]
        public GameObject GameObject;
        [NonSerialized]
        public Animation Animation;
        [NonSerialized]
        public Action RefreshAction;

        //是否场景里面的物件,这种物件是不能销毁的
        [NonSerialized]
        private bool _isSceneObj = false;
        //当前是camera,只有等到第一个有事件的帧才能显现出来
        [NonSerialized]
        private bool _isCameraCanShow = true;
        //包含位移的关键帧
        [NonSerialized]
        public List<CinematicKeyframe> TransKeyframeList;
        //关键帧图片宽度
        private int _keyFrameIconWidth = 15;
        [NonSerialized]
        public Dictionary<int, CinematicKeyframe> KeyframeDict;

        public override void WriteAll(BinaryWriter bw)
        {
            //写入顺序必须按照上面成员定义的顺序,读取亦然
            PrepareWriter(bw);
            WriteInt(EventType);
            WriteList(KeyframeList);
            WriteString(Name);
            WriteInt(CurFrame);
            WriteInt(FrameRate);
            WriteBool(IsCamera);
            WriteInt(CameraDepth);
            WriteInt(LayMask);
            WriteV3Array(PathV3Array);
        }

        public override void ReadAll(BinaryReader rd)
        {
            PrepareReader(rd);
            EventType = ReadInt();
            KeyframeList = ReadList<CinematicKeyframe>();
            Name = ReadString();
            CurFrame =ReadInt();
            FrameRate = ReadInt();
            IsCamera = ReadBool();
            CameraDepth = ReadInt();
            if (CameraDepth < 10)
                CameraDepth = 10;
            LayMask = ReadInt();
            PathV3Array = ReadV3Array();
        }

        public CinematicObj()
        {
            KeyframeList = new List<CinematicKeyframe>();
            TransKeyframeList = new List<CinematicKeyframe>();
            Name = GetType().Name;
        }

        public CinematicObj(string name)
        {
            KeyframeList = new List<CinematicKeyframe>();
            TransKeyframeList = new List<CinematicKeyframe>();
            Name = name;
            InitGameObject();
        }

        //保存之前,调用一次这个函数
        public void SortKeyframe()
        {
            KeyframeList.Sort((a, b) => { return a.Keyframe - b.Keyframe; });
            KeyframeDict = new Dictionary<int, CinematicKeyframe>();
            for (int i = 0; i < KeyframeList.Count; ++i)
            {
                if (i - 1 >= 0)
                    KeyframeList[i].PreEventData = KeyframeList[i - 1];
                else
                    KeyframeList[i].PreEventData = null;

                if (i + 1 < KeyframeList.Count)
                    KeyframeList[i].NextKeyframe = KeyframeList[i + 1];
                else
                    KeyframeList[i].NextKeyframe = null;

                KeyframeDict.Add(KeyframeList[i].Keyframe, KeyframeList[i]);

                KeyframeList[i].RemoveTransEventWhileHasSyncEvent();

                //runtime 使用
                for(int m = 0; m < KeyframeList[i].EventData.Count; ++m)
                {
                    if(KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.坐标变换)
                    {
                        KeyframeList[i].TransformEvent = KeyframeList[i].EventData[m];
                        TransKeyframeList.Add(KeyframeList[i]);
                    }
                    if(KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.同步到本地相机坐标 ||
                        KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.同步到本地角色坐标)
                    {
                        KeyframeList[i].HasSyncTrans = true;
                    }
                    if(KeyframeList[i].EventData[m].EventTypeEx == KeyFrameEvent.播放动作)
                    {
                        KeyframeList[i].AnimEvent = KeyframeList[i].EventData[m];
                    }
                }
            }

            //给当前帧赋值下一个含有位移的关键帧
            for (int n = 1; n < KeyframeList.Count; ++n)
            {
                var curKeyframe = KeyframeList[n - 1];
                curKeyframe.NextTransKeyframe = null;
                var nextKeyframe = KeyframeList[n];
                while (nextKeyframe != null)
                {
                    if (nextKeyframe.TransformEvent != null)
                    {
                        curKeyframe.NextTransKeyframe = nextKeyframe;
                        break;
                    }
                    nextKeyframe = nextKeyframe.NextKeyframe;
                }
            }
        }

        public CinematicKeyframe GetKeyframeData(int frame)
        {
            InitDicData();

            CinematicKeyframe ret = null;
            KeyframeDict.TryGetValue(frame, out ret);
            return ret;
        }

        private void InitDicData()
        {
            if(KeyframeDict == null)
            {
                KeyframeDict = new Dictionary<int, CinematicKeyframe>();
                for (int i = 0; i < KeyframeList.Count; ++i)
                {
                    if (i - 1 >= 0)
                        KeyframeList[i].PreEventData = KeyframeList[i - 1];
                    else
                        KeyframeList[i].PreEventData = null;

                    if (i + 1 < KeyframeList.Count)
                        KeyframeList[i].NextKeyframe = KeyframeList[i + 1];
                    else
                        KeyframeList[i].NextKeyframe = null;

                    KeyframeDict.Add(KeyframeList[i].Keyframe, KeyframeList[i]);
                }
            }
        }

        public CinematicKeyframe GetPreTransKeyframeData(int frame)
        {
            CinematicKeyframe ret = null;
            for(int i = KeyframeList.Count - 1; i >= 0; --i)
            {
                if(KeyframeList[i].Keyframe < frame && KeyframeList[i].GetTransEvent() != null)
                {
                    ret = KeyframeList[i];
                    break;
                }
            }

            return ret;
        }

        public CinematicKeyframe GetPreAnimKeyframeData(int frame)
        {
            CinematicKeyframe ret = null;
            for (int i = KeyframeList.Count - 1; i >= 0; --i)
            {
                if (KeyframeList[i].Keyframe < frame && KeyframeList[i].GetAnimEvent() != null)
                {
                    ret = KeyframeList[i];
                    break;
                }
            }

            return ret;
        }

        public bool ExistFrame(int frame, out CinematicKeyframe keyFrameData)
        {
            keyFrameData = null;
            for (int i = 0; i < KeyframeList.Count; ++i)
            {
                if (KeyframeList[i].Keyframe == frame)
                {
                    keyFrameData = KeyframeList[i];
                    return true;
                }
            }

            return false;
        }

        public bool ExistFrame(int frame)
        {
            for (int i = 0; i < KeyframeList.Count; ++i)
            {
                if (KeyframeList[i].Keyframe == frame)
                {
                    return true;
                }
            }

            return false;
        }

        public void AddEvent(int frame, KeyFrameEvent e)
        {
            CinematicKeyframe eData;
            if(ExistFrame(frame, out eData))
            {
                eData.AddEvent(new CinematicEventData(e));
            }
        }

        public bool IsEndFrame(int frame)
        {
            if (KeyframeList == null || KeyframeList.Count == 0) return true;

            return KeyframeList[KeyframeList.Count - 1].Keyframe <= frame;
        }

        //添加关键帧
        public CinematicKeyframe AddFrame(int frame)
        {
            CinematicKeyframe keyFrameData;
            if (ExistFrame(frame, out keyFrameData))
            {
                keyFrameData.SetData(frame);
            }
            else
            {
                keyFrameData = new CinematicKeyframe();
                keyFrameData.SetData(frame);

                KeyframeList.Add(keyFrameData);
            }

            keyFrameData.Selected = true;

            CurFrame = frame;

            return keyFrameData;
        }

        //移除关键帧
        public void RemoveFrame(int frame)
        {
            CinematicKeyframe keyFrameData = null;
            if (ExistFrame(frame, out keyFrameData))
            {
                KeyframeList.Remove(keyFrameData);
                keyFrameData.OnRefreshEditor(true);
            }
        }

        //复制关键帧
        public List<CinematicEventData> CopyFrameData(int frame)
        {
            CinematicKeyframe keyFrameData;
            List<CinematicEventData> retList = new List<CinematicEventData>();
            if (!ExistFrame(frame, out keyFrameData)) return retList;

            retList = keyFrameData.CloneEventData();
            return retList;
        }

        //粘贴关键帧
        public void PasteFrameData(int frame, List<CinematicEventData> eData)
        {
            CinematicKeyframe keyFrameData;
            if (ExistFrame(frame, out keyFrameData))
            {
                keyFrameData.SetData(frame, eData);
            }
            else
            {
                keyFrameData = new CinematicKeyframe();
                keyFrameData.SetData(frame, eData);
                KeyframeList.Add(keyFrameData);
            }
            keyFrameData.Selected = true;

            CurFrame = frame;
        }

        public void ClearSelectState()
        {
            for(int i = 0; i < KeyframeList.Count; ++i)
            {
                KeyframeList[i].Selected = false;
            }
        }

        public void SetSelectState(int frame)
        {
            CinematicKeyframe keyFrameData;
            if(ExistFrame(frame, out keyFrameData))
            {
                keyFrameData.SetSelected();
            }
        }

        public void MoveFrameWhileDrag(int deltaFrame)
        {
            for(int i = 0; i < KeyframeList.Count; ++i)
            {
                if(KeyframeList[i].Selected)
                {
                    KeyframeList[i].Keyframe += deltaFrame;
                    if(KeyframeList[i].Keyframe < 0)
                    {
                        KeyframeList[i].Keyframe = 0;
                    }

                    KeyframeList[i].OnRefreshEditor();
                }
            }

            ResetTransState();
            SortKeyframe();

            RefreshEditorData();
        }

        public void RefreshEditorData()
        {
            if (RefreshAction != null) RefreshAction();
        }

        static Vector3 CalculateLinearVector(Vector3 start, Vector3 end, float t, float t2)
        {
            float distance = (end - start).magnitude;
            Vector3 deltaV3 = end - start;
            Vector3 dir = (end - start).normalized;
            Vector3 newStart = start + (dir * distance / (t)) * t2;
            return newStart;
        }

        static Quaternion CalculateLinearQuaternion(Quaternion from, Quaternion to, float t, float t2)
        {
            return Quaternion.Slerp(from, to, (1f / (t)) * t2);
        }

        #region runtime

        [NonSerialized]
        private bool _hasNextTransform = true;
        [NonSerialized]
        private CinematicEventData _nextTransEvent;
        [NonSerialized]
        private List<GameObject> _childrenGO;

        public void Prepare()
        {
            SortKeyframe();
            ResetTransState();
            InitGameObject();
        }

        public void ResetTransState()
        {
            _nextTransEvent = null;
            _hasNextTransform = true;
        }

        public void InitGameObject()
        {
            if (GameObject == null)
            {
                _childrenGO = new List<GameObject>();
                GameObject = new GameObject(Name);
                GameObject.transform.parent = CinematicManager.RootGo.transform;

                if(IsCamera)
                {
                    GameObject.name = "Camera";
                    var camera = GameObject.AddComponent<Camera>();
                    camera.depth = CameraDepth;
                    camera.cullingMask = LayMask;
                    GameObject.SetActive(false);
                    _isCameraCanShow = false;
                }
#if UNITY_EDITOR //编辑器下描绘曲线
                var script = GameObject.AddComponent<Plugin.CinematicUI_Curve>();
                script.CinematicObj = this;
#endif
            }
        }

        public void SetCameraLayerMask(int layerMask)
        {
            LayMask = layerMask;
            if (GameObject == null) return;

            Camera camera = GameObject.GetComponent<Camera>();
            if(camera != null)
            {
                camera.cullingMask = LayMask;
                camera.depth = CameraDepth;
            }
        }

        public void ClearChild()
        {
            if (_childrenGO == null) return;

            for(int i = 0; i < _childrenGO.Count; ++i)
            {
#if UNITY_EDITOR
                GameObject.DestroyImmediate(_childrenGO[i]);
#else
                GameObject.Destroy(_childrenGO[i]);
#endif

            }

            _childrenGO.Clear();
        }

        public void Destory()
        {

            if (GameObject != null && !_isSceneObj)
            {

#if UNITY_EDITOR
                GameObject.DestroyImmediate(GameObject);
#else
                GameObject.Destroy(GameObject);
#endif
            }
            if(_childrenGO != null) _childrenGO.Clear();
        }

        public void LoadPrefab(string param, string editorParam, bool isLocalPlayer = false)
        {
            _isSceneObj = false;
            ClearChild();
            {
                UnityEngine.Debug.LogWarning("Use editor load prefab!!!");
                //if (CinematicObjManager.IsEditorPreview && !string.IsNullOrEmpty(editorParam))
                {
                    GameObject go = GameObject.Instantiate(Resources.Load<GameObject>(editorParam)) as GameObject;
                    go.transform.parent = GameObject.transform;

                    go.transform.localPosition = Vector3.zero;
                    go.transform.localScale = Vector3.one;
                    go.transform.localRotation = Quaternion.identity;
                    _childrenGO.Add(go);

                    Animation = go.GetComponent<Animation>();

                    //return;
                }
            }
        }

        public void LoadPrefabFromScene(string nodeFullPath)
        {
            //不做clear,可能会删除掉场景中的物件
            //ClearChild();
            _isSceneObj = true;
            GameObject = GameObject.Find(nodeFullPath);
            Animation = GameObject.GetComponent<Animation>();
        }

        public void SetTransform(CinematicEventData data)
        {
            if (GameObject == null) return;
            SetCameraVisiable();
            GameObject.transform.localPosition = data.Position;
            GameObject.transform.localScale = data.Scale;
            GameObject.transform.localRotation = Quaternion.Euler(data.Rotation);
        }

        public void SetCameraVisiable()
        {
            if (IsCamera && !_isCameraCanShow)
            {
                GameObject.SetActive(true);
                _isCameraCanShow = true;
            }
        }

        //曲线变换
        public void SetTransformCurveTo(CinematicEventData preTransData, CinematicKeyframe curKeyframe, float preKeyframe, float deltaFrame)
        {
            if (IsCamera && !_isCameraCanShow)
            {
                GameObject.SetActive(true);
                _isCameraCanShow = true;
            }

            var nextKeyframe = deltaFrame > 0 ? curKeyframe.NextTransKeyframe: curKeyframe.PreEventData;
            if (!_hasNextTransform || nextKeyframe == null || GameObject == null) return;
            _nextTransEvent = nextKeyframe.TransformEvent;
            float durationFame = nextKeyframe.Keyframe - preKeyframe;

            if (durationFame > 0)
            {
                if (deltaFrame < 0) deltaFrame = durationFame + deltaFrame;
                //路点小于2,用线性差值 或者不使用曲线
                if (PathV3Array.Length < 2 || !curKeyframe.TransformEvent.UseCurve)
                {
                    GameObject.transform.localPosition = CalculateLinearVector(preTransData.Position, _nextTransEvent.Position, durationFame, deltaFrame);
                }
                else
                {
                    //去掉曲线影响,相同的两个点还会产生位移的情况
                    if (curKeyframe.TransformEvent.Position == nextKeyframe.TransformEvent.Position)
                    {
                        GameObject.transform.localPosition = curKeyframe.TransformEvent.Position;
                        curKeyframe.TransPercentageInCurve = nextKeyframe.TransPercentageInCurve;
                    }
                    else
                    {
                        //偏移量/活动区间 = 该区域移动百分比
                        float percent = (deltaFrame / durationFame) * (nextKeyframe.TransPercentageInCurve - curKeyframe.TransPercentageInCurve) + curKeyframe.TransPercentageInCurve;

                        Vector3 curvPos = CinematicSerialize.Interp(PathV3Array, percent);
                        //Vector3 newDir = (curvPos - GameObject.transform.localPosition);
                        //newDir.y = 0;
                        //GameObject.transform.forward = newDir;
                        GameObject.transform.localPosition = curvPos;
                    }
                }

                GameObject.transform.localScale = CalculateLinearVector(preTransData.Scale, _nextTransEvent.Scale, durationFame, deltaFrame);
                GameObject.transform.localRotation = CalculateLinearQuaternion(Quaternion.Euler(preTransData.Rotation), Quaternion.Euler(_nextTransEvent.Rotation), durationFame, deltaFrame);
            }
        }

        //线性变换
        public void SetTransform(CinematicEventData fromTrans, CinematicEventData toTrans, float durationFrame, float deltaFrame)
        {
            if (GameObject == null || fromTrans == null || toTrans == null || durationFrame == 0) return;
            GameObject.transform.localPosition = CalculateLinearVector(fromTrans.Position, toTrans.Position, durationFrame, deltaFrame);
            GameObject.transform.localScale = CalculateLinearVector(fromTrans.Scale, toTrans.Scale, durationFrame, deltaFrame);
            GameObject.transform.localRotation = CalculateLinearQuaternion(Quaternion.Euler(fromTrans.Rotation), Quaternion.Euler(toTrans.Rotation), durationFrame, deltaFrame);
        }

        //播放动作,支持逐帧播放
        public void PlayAnimationByFrame(CinematicEventData eventData, int keyframe, float curFrame)
        {
            if (Animation != null && eventData != null && curFrame >= keyframe && eventData.IsLocalPlayer)
            {
                var animEvent = eventData;
                if (Animation[animEvent.Param] != null)
                {
                    {
                        float durationFame = curFrame - keyframe;
                        AnimationState state = Animation[animEvent.Param];
                        AnimationClip clip = Animation.GetClip(animEvent.Param);
                        float length = state.length;
                        float totalFrame = length * 30;// clip.frameRate;
                        float deltaTime = (durationFame / totalFrame);
                        float speed = 1;
                        if (!string.IsNullOrEmpty(eventData.EditorParam))
                        {
                            if (!float.TryParse(eventData.EditorParam, out speed))
                                speed = 1;
                        }
                        deltaTime *= speed;
                        if (animEvent.WrapMode == WrapMode.Loop)
                        {
                            if (deltaTime > 1.0f)
                            {
                                deltaTime = deltaTime - (float)Math.Truncate(deltaTime);
                            }
                        }
                        state.normalizedTime = deltaTime;
                        state.normalizedSpeed = 0;
                    }
                    
                    Animation.Play(animEvent.Param);
                }
            }
        }

        //播放动作,不按照帧播放
        public void PlayAnimation(CinematicEventData eventData)
        {
            if (Animation != null && eventData != null)
            {
                var animEvent = eventData;
                if (Animation[animEvent.Param] != null)
                {
                    Animation.Stop();
                    var state = Animation[animEvent.Param];
                    state.wrapMode = eventData.WrapMode;
                    float speed = 1;
                    if (!string.IsNullOrEmpty(eventData.EditorParam))
                    {
                        if (!float.TryParse(eventData.EditorParam, out speed))
                            speed = 1;
                    }
                    state.speed = speed;
                    Animation.Play(animEvent.Param);
                }
            }
        }

        public void Update()
        {
        }

        public void EditorUpdate()
        {
            if (GameObject != null)
                Name = GameObject.name;
        }
#endregion
    }
}