using DG.Tweening;
using FL.Battle.Actions;
using System;
using UnityEngine;
using XGame.Framework;
using XGame.Framework.Components;
using XGame.Framework.Map;
using XGame.Framework.Time;

namespace FL.Battle.Components
{
    public interface IMoveContext
    {
        /// <summary>
        /// 所有者的根节点
        /// </summary>
        Transform OwnerTr { get; }
    }
    public enum EMoveType
    {
        /// <summary>
        /// 直线运动
        /// DoTween.DOMove
        /// </summary>
        Line = 0,
        /// <summary>
        /// 贝塞尔曲线轨迹
        /// </summary>
        Bezier,
        /// <summary>
        /// 抛物线
        /// </summary>
        Parabola,
    }
    /// <summary>
    /// 移动参数
    /// </summary>
    public struct MoveArgs
    {
        public Vector3 target;
        public float speed;
        /// <summary>
        /// 时间缩放值，默认需要传1
        /// </summary>
        public float timeScale;
        public EMoveType moveType;
        public Ease ease;
        /// <summary>
        /// 延迟，单位: 毫秒
        /// </summary>
        public int delay;
        //public Action<Vector3> onUpdate;
        public Action onComplete;
    }
    /// <summary>
    /// DoTween.DOLocalMoveY 
    /// </summary>
    public class MoveComponent : Component<IMoveContext>, IParallelTarget, IPauseable, ITimeScalable
    {
        private IAction _action;
        public Vector3 MoveDir { get; private set; }
        public bool IsMoving => _action != null;

        Vector3 IParallelTarget.Position => Context.OwnerTr.position;
        public float TimeScale
        {
            get
            {
                if (_action is ITimeScalable scalable)
                {
                    return scalable.TimeScale;
                }
                return 1;
            }
            set
            {
                if (_action is ITimeScalable scalable)
                {
                    scalable.TimeScale = value;
                }
            }
        }
        public void MoveTo(MoveArgs args)
        {
            var position = Context.OwnerTr.position;
            var duration = Mathf.RoundToInt(Vector3.Distance(args.target, position) * 1000 / args.speed);
            MoveDir = Vector3.Normalize(args.target - position);
            void OnCompleted()
            {
                ObjectPool.Recycle(_action);
                _action = null;
                MoveDir = Vector3.zero;
                args.onComplete.SafeInvoke();
            }
            var actionArgs = new MoveActionArgs()
            {
                from = position,
                to = args.target,
                duration = duration,
                delay = args.delay,
                ease = args.ease,
                //onUpdate = args.onUpdate,
                onComplete = OnCompleted
            };

            if (args.moveType == EMoveType.Line)
            {
                var move = ObjectPool.Acquire<MoveLineAction>();
                _action = move;
                move.args = actionArgs;
                move.Start(Context.OwnerTr);
            }
            else if (args.moveType == EMoveType.Bezier)
            {
                var move = ObjectPool.Acquire<MoveBezierAction>();
                _action = move;
                move.args = actionArgs;
                move.Start(Context.OwnerTr, false);
            }
            else
            {
                var move = ObjectPool.Acquire<MoveParabolaAction>();
                _action = move;
                move.args = actionArgs;
                move.Start(Context.OwnerTr);
            }
            if (args.timeScale != 1)
            {
                TimeScale = args.timeScale;
            }
        }

        public void Pause()
        {
            (_action as IPauseable)?.Pause();
        }

        public void Resume()
        {
            (_action as IPauseable)?.Resume();
        }

        public void StopMove()
        {
            if (_action != null)
            {
                ObjectPool.Recycle(_action);
                _action = null;
                MoveDir = Vector3.zero;
            }
        }
        protected override void OnDispose()
        {
            StopMove();
        }
    }
}
