using FishNet.Object;
using FishNet.Object.Synchronizing;
using UnityEngine;

namespace IStalk.Runner
{
    public class RunnerAnimator : NetworkBehaviour
    {
        [SerializeField] private Animator _animator;

        private readonly SyncVar<byte> _animState = new(new SyncTypeSettings(0.05f));
        private readonly SyncVar<float> _moveSpeed = new(new SyncTypeSettings(0.1f));

        private static readonly int SpeedHash = Animator.StringToHash("Speed");
        private static readonly int GroundedHash = Animator.StringToHash("Grounded");
        private static readonly int JumpHash = Animator.StringToHash("Jump");
        private static readonly int SlideHash = Animator.StringToHash("Slide");
        private static readonly int WallRunHash = Animator.StringToHash("WallRun");
        private static readonly int DownedHash = Animator.StringToHash("Downed");

        private RunnerController _controller;
        private CharacterController _cc;
        private RunnerHealth _health;
        private byte _lastState;

        public override void OnStartNetwork()
        {
            base.OnStartNetwork();
            _controller = GetComponent<RunnerController>();
            _cc = GetComponent<CharacterController>();
            _health = GetComponent<RunnerHealth>();
            _animState.OnChange += OnAnimStateChanged;
            _moveSpeed.OnChange += OnMoveSpeedChanged;
        }

        private void Update()
        {
            if (!IsServerStarted) return;
            if (_controller == null || _cc == null) return;

            float speed = new Vector2(_cc.velocity.x, _cc.velocity.z).magnitude;
            _moveSpeed.Value = speed;

            byte state = 0;
            if (_health != null && _health.IsDown) state = 5;
            else
            {
                state = _controller.GetMoveState() switch
                {
                    RunnerController.MoveState.Normal => (byte)(_cc.isGrounded ? 0 : 1),
                    RunnerController.MoveState.WallRunning => 2,
                    RunnerController.MoveState.Sliding => 3,
                    RunnerController.MoveState.Dashing => 4,
                    RunnerController.MoveState.Vaulting => 4,
                    RunnerController.MoveState.Mantling => 4,
                    _ => 0
                };
            }

            if (state != _lastState)
            {
                _animState.Value = state;
                _lastState = state;
            }
        }

        private void OnAnimStateChanged(byte prev, byte next, bool asServer)
        {
            if (_animator == null) return;

            _animator.SetBool(GroundedHash, next == 0);
            _animator.SetBool(SlideHash, next == 3);
            _animator.SetBool(WallRunHash, next == 2);
            _animator.SetBool(DownedHash, next == 5);

            if (next == 1 && prev == 0)
                _animator.SetTrigger(JumpHash);
        }

        private void OnMoveSpeedChanged(float prev, float next, bool asServer)
        {
            if (_animator != null)
                _animator.SetFloat(SpeedHash, next);
        }
    }
}
