using System;
using UnityEngine;
namespace XCharts.Runtime
{
    /// 
    /// the animation info.
    /// ||动画配置参数。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationInfo
    {
        [SerializeField][Since("v3.8.0")] private bool m_Enable = true;
        [SerializeField][Since("v3.8.0")] private bool m_Reverse = false;
        [SerializeField][Since("v3.8.0")] private float m_Delay = 0;
        [SerializeField][Since("v3.8.0")] private float m_Duration = 1000;
        public AnimationInfoContext context = new AnimationInfoContext();
        /// 
        /// whether enable animation.
        /// ||是否开启动画效果。
        /// 
        public bool enable { get { return m_Enable; } set { m_Enable = value; } }
        /// 
        /// whether enable reverse animation.
        /// ||是否开启反向动画效果。
        /// 
        public bool reverse { get { return m_Reverse; } set { m_Reverse = value; } }
        /// 
        /// the delay time before animation start.
        /// ||动画开始前的延迟时间。
        /// 
        public float delay { get { return m_Delay; } set { m_Delay = value; } }
        /// 
        /// the duration of animation.
        /// ||动画的时长。
        /// 
        public float duration { get { return m_Duration; } set { m_Duration = value; } }
        /// 
        /// the callback function of animation start.
        /// ||动画开始的回调。
        /// 
        public Action OnAnimationStart { get; set; }
        /// 
        /// the callback function of animation end.
        /// ||动画结束的回调。
        /// 
        public Action OnAnimationEnd { get; set; }
        /// 
        /// the delegate function of animation delay.
        /// ||动画延迟的委托函数。
        /// 
        public AnimationDelayFunction delayFunction { get; set; }
        /// 
        /// the delegate function of animation duration.
        /// ||动画时长的委托函数。
        /// 
        public AnimationDurationFunction durationFunction { get; set; }
        /// 
        /// Reset animation.
        /// ||重置动画。
        /// 
        public void Reset()
        {
            if (!enable) return;
            context.init = false;
            context.start = false;
            context.pause = false;
            context.end = false;
            context.startTime = 0;
            context.currProgress = 0;
            context.destProgress = 0;
            context.totalProgress = 0;
            context.sizeProgress = 0;
            context.currPointIndex = 0;
            context.currPoint = Vector3.zero;
            context.destPoint = Vector3.zero;
            context.dataCurrProgress.Clear();
            context.dataDestProgress.Clear();
        }
        /// 
        /// Start animation.
        /// ||开始动画。
        /// 
        /// 是否重置上一次的参数
        public void Start(bool reset = true)
        {
            if (!enable) return;
            if (context.start)
            {
                context.pause = false;
                return;
            }
            context.init = false;
            context.start = true;
            context.end = false;
            context.pause = false;
            context.startTime = Time.time;
            if (reset)
            {
                context.currProgress = 0;
                context.destProgress = 1;
                context.totalProgress = 0;
                context.sizeProgress = 0;
                context.dataCurrProgress.Clear();
                context.dataDestProgress.Clear();
            }
            if (OnAnimationStart != null)
            {
                OnAnimationStart();
            }
        }
        /// 
        /// Pause animation.
        /// ||暂停动画。
        /// 
        public void Pause()
        {
            if (!enable) return;
            if (!context.start || context.end) return;
            context.pause = true;
        }
        /// 
        /// Resume animation.
        /// ||恢复动画。
        /// 
        public void Resume()
        {
            if (!enable) return;
            if (!context.pause) return;
            context.pause = false;
        }
        /// 
        /// End animation.
        /// ||结束动画。
        /// 
        public void End()
        {
            if (!enable) return;
            if (!context.start || context.end) return;
            context.start = false;
            context.end = true;
            context.currPointIndex = context.destPointIndex;
            context.startTime = Time.time;
            if (OnAnimationEnd != null)
            {
                OnAnimationEnd();
            }
        }
        /// 
        /// Initialize animation.
        /// ||初始化动画。
        /// 
        /// 当前进度
        /// 目标进度
        /// 目标索引
        /// 
        public bool Init(float curr, float dest, int totalPointIndex)
        {
            if (!enable || !context.start) return false;
            if (context.init || context.end) return false;
            context.init = true;
            context.totalProgress = dest - curr;
            context.destPointIndex = totalPointIndex;
            if (reverse)
            {
                context.currProgress = dest;
                context.destProgress = curr;
            }
            else
            {
                context.currProgress = curr;
                context.destProgress = dest;
            }
            return true;
        }
        /// 
        /// Whether animation is finish.
        /// ||动画是否结束。
        /// 
        public bool IsFinish()
        {
            if (!context.start) return true;
            if (context.end) return true;
            if (context.pause) return false;
            if (!context.init) return false;
            return m_Reverse ? context.currProgress <= context.destProgress
                : context.currProgress >= context.destProgress;
        }
        /// 
        /// Whether animation is in delay.
        /// ||动画是否在延迟中。
        /// 
        public bool IsInDelay()
        {
            if (!context.start)
                return false;
            else
                return (m_Delay > 0 && Time.time - context.startTime < m_Delay / 1000);
        }
        /// 
        /// Whether animation is in index delay.
        /// ||动画是否在索引延迟中。
        /// 
        /// 
        /// 
        public bool IsInIndexDelay(int dataIndex)
        {
            if (context.start)
                return Time.time - context.startTime < GetIndexDelay(dataIndex) / 1000f;
            else
                return false;
        }
        /// 
        /// Get animation delay.
        /// ||获取动画延迟。
        /// 
        /// 
        /// 
        public float GetIndexDelay(int dataIndex)
        {
            if (!context.start) return 0;
            if (delayFunction != null)
                return delayFunction(dataIndex);
            return delay;
        }
        internal float GetCurrAnimationDuration(int dataIndex = -1)
        {
            if (dataIndex >= 0)
            {
                if (context.start && durationFunction != null)
                    return durationFunction(dataIndex) / 1000f;
            }
            return m_Duration > 0 ? m_Duration / 1000 : 1f;
        }
        internal void SetDataCurrProgress(int index, float state)
        {
            context.dataCurrProgress[index] = state;
        }
        internal float GetDataCurrProgress(int index, float initValue, float destValue, ref bool isBarEnd)
        {
            if (IsInDelay())
            {
                isBarEnd = false;
                return initValue;
            }
            var c1 = !context.dataCurrProgress.ContainsKey(index);
            var c2 = !context.dataDestProgress.ContainsKey(index);
            if (c1 || c2)
            {
                if (c1)
                    context.dataCurrProgress.Add(index, initValue);
                if (c2)
                    context.dataDestProgress.Add(index, destValue);
                isBarEnd = false;
            }
            else
            {
                isBarEnd = context.dataCurrProgress[index] == context.dataDestProgress[index];
            }
            return context.dataCurrProgress[index];
        }
        internal void CheckProgress(double total, bool m_UnscaledTime)
        {
            if (!context.start || !context.init || context.pause) return;
            if (IsInDelay()) return;
            var duration = GetCurrAnimationDuration();
            var delta = (float)(total / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime));
            if (reverse)
            {
                context.currProgress -= delta;
                if (context.currProgress <= context.destProgress)
                {
                    context.currProgress = context.destProgress;
                    End();
                }
            }
            else
            {
                context.currProgress += delta;
                if (context.currProgress >= context.destProgress)
                {
                    context.currProgress = context.destProgress;
                    End();
                }
            }
        }
        internal float CheckItemProgress(int dataIndex, float destProgress, ref bool isEnd, float startProgress, bool m_UnscaledTime)
        {
            if (m_Reverse)
            {
                var temp = startProgress;
                startProgress = destProgress;
                destProgress = temp;
            }
            var currHig = GetDataCurrProgress(dataIndex, startProgress, destProgress, ref isEnd);
            if (IsFinish())
            {
                return destProgress;
            }
            else if (IsInDelay() || IsInIndexDelay(dataIndex))
            {
                return startProgress;
            }
            else if (context.pause)
            {
                return currHig;
            }
            else
            {
                var duration = GetCurrAnimationDuration(dataIndex);
                var delta = (destProgress - startProgress) / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime);
                currHig += delta;
                if (reverse)
                {
                    if ((destProgress > 0 && currHig <= 0) || (destProgress < 0 && currHig >= 0))
                    {
                        currHig = 0;
                        isEnd = true;
                    }
                }
                else
                {
                    if ((destProgress - startProgress > 0 && currHig > destProgress) ||
                        (destProgress - startProgress < 0 && currHig < destProgress))
                    {
                        currHig = destProgress;
                        isEnd = true;
                    }
                }
                SetDataCurrProgress(dataIndex, currHig);
                return currHig;
            }
        }
        internal void CheckSymbol(float dest, bool m_UnscaledTime)
        {
            if (!context.start || !context.init || context.pause) return;
            if (IsInDelay())
                return;
            var duration = GetCurrAnimationDuration();
            var delta = dest / duration * (m_UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime);
            if (reverse)
            {
                context.sizeProgress -= delta;
                if (context.sizeProgress < 0)
                    context.sizeProgress = 0;
            }
            else
            {
                context.sizeProgress += delta;
                if (context.sizeProgress > dest)
                    context.sizeProgress = dest;
            }
        }
    }
    /// 
    /// Fade in animation.
    /// ||淡入动画。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationFadeIn : AnimationInfo
    {
    }
    /// 
    /// Fade out animation.
    /// ||淡出动画。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationFadeOut : AnimationInfo
    {
    }
    /// 
    /// Data change animation.
    /// ||数据变更动画。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationChange : AnimationInfo
    {
    }
    /// 
    /// Data addition animation.
    /// ||数据新增动画。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationAddition : AnimationInfo
    {
    }
    /// 
    /// Data hiding animation.
    /// ||数据隐藏动画。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationHiding : AnimationInfo
    {
    }
    /// 
    /// Interactive animation of charts.
    /// ||交互动画。
    /// 
    [Since("v3.8.0")]
    [System.Serializable]
    public class AnimationInteraction : AnimationInfo
    {
        [SerializeField][Since("v3.8.0")] private MLValue m_Width = new MLValue(1.1f);
        [SerializeField][Since("v3.8.0")] private MLValue m_Radius = new MLValue(1.1f);
        [SerializeField][Since("v3.8.0")] private MLValue m_Offset = new MLValue(MLValue.Type.Absolute, 5f);
        /// 
        /// the mlvalue of width.
        /// ||宽度的多样式数值。
        /// 
        public MLValue width { get { return m_Width; } set { m_Width = value; } }
        /// 
        /// the mlvalue of radius.
        /// ||半径的多样式数值。
        /// 
        public MLValue radius { get { return m_Radius; } set { m_Radius = value; } }
        /// 
        /// the mlvalue of offset. Such as the offset of the pie chart when the sector is selected.
        /// ||交互的多样式数值。如饼图的扇形选中时的偏移。
        /// 
        public MLValue offset { get { return m_Offset; } set { m_Offset = value; } }
        public float GetRadius(float radius)
        {
            return m_Radius.GetValue(radius);
        }
        public float GetWidth(float width)
        {
            return m_Width.GetValue(width);
        }
        public float GetOffset(float total)
        {
            return m_Offset.GetValue(total);
        }
        public float GetOffset()
        {
            return m_Offset.value;
        }
    }
}