using LeMangeurDEnfants.Core.Scenes;
using Microsoft.Xna.Framework;
using MonoGame.FourEngine;
using System;
using System.Collections.Generic;
using System.Linq;
using static MonoGame.FourEngine.Components.AnimationComponent;

namespace LeMangeurDEnfants.Core.Entities
{
    public class Follower : BaseObject, IFollower
    {
        public override Point Size { get; } = new Point(19);
        public override string FileName { get; } = Resources.Sprites.Follower;
        public const float Speed = 32f;

        public IFollower NextFollower { get; set; }

        public Direction NextDirection { get; set; }
        public Direction CurrentDirection
        {
            get => _currentDirection;
            set
            {
                _currentDirection = value;
                AnimationComponent.StartAnimation(
                    FramedAnimation.GenerateRange(
                        new Range(0, 8),
                        (int)_currentDirection + 1,
                        160, true));
            }
        }

        private Queue<NavigationNode> _navigation = new Queue<NavigationNode>();
        private Vector2 _positionVector;
        private Direction _currentDirection;

        private bool _isActive;
        private bool _isDead;

        private IHaveFollower _owner;
        private Point _previousOwnerPosition;
        private int _distanceFromOwner;

        public void AddNavigationNode(NavigationNode node)
        {
            _navigation.Enqueue(node);
        }
        
        public void Init(Prisoner prisoner, IHaveFollower owner)
        {
            Position = owner.Position;
            _positionVector = Position.ToVector2();
            _owner = owner;
            _previousOwnerPosition = owner.Position;
        }

        public void Fail()
        {
            _isDead = true;
            AnimationComponent.StopAnimation();
            SpriteComponent.Frame = new Point(1, 0);
            NextFollower?.Fail();
        }

        public override void OnUpdate(UpdateEventArgs args)
        {
            base.OnUpdate(args);
            if (_isDead) return;

            if (!_isActive)
            {
                var ownerPositionChange = _owner.Position - _previousOwnerPosition;
                var ownerDistanceTraveled = Math.Abs(ownerPositionChange.X) + Math.Abs(ownerPositionChange.Y);
                _distanceFromOwner += ownerDistanceTraveled;
                _previousOwnerPosition = _owner.Position;
                if (_distanceFromOwner > 24)
                {
                    _isActive = true;
                    CurrentDirection = NextDirection;
                }
                return;
            }

            var speed = Speed * (float)args.DeltaTime.TotalMilliseconds / 1000f;
            switch (CurrentDirection)
            {
                case Direction.Left:
                    _positionVector += new Vector2(-speed, 0);
                    break;
                case Direction.Up:
                    _positionVector += new Vector2(0, -speed);
                    break;
                case Direction.Right:
                    _positionVector += new Vector2(speed, 0);
                    break;
                case Direction.Down:
                    _positionVector += new Vector2(0, speed);
                    break;
            }
            if (_navigation.Any() && _navigation.Peek() is NavigationNode node)
            {
                switch (CurrentDirection)
                {
                    case Direction.Left:
                        if (Position.X <= node.Trigger.X)
                        {
                            _navigation.Dequeue();
                            CurrentDirection = node.Direction;
                            NotifyFollower();
                        }
                        break;
                    case Direction.Up:
                        if (Position.Y <= node.Trigger.Y)
                        {
                            _navigation.Dequeue();
                            CurrentDirection = node.Direction;
                            NotifyFollower();
                        }
                        break;
                    case Direction.Right:
                        if (Position.X >= node.Trigger.X)
                        {
                            _navigation.Dequeue();
                            CurrentDirection = node.Direction;
                            NotifyFollower();
                        }
                        break;
                    case Direction.Down:
                        if (Position.Y >= node.Trigger.Y)
                        {
                            _navigation.Dequeue();
                            CurrentDirection = node.Direction;
                            NotifyFollower();
                        }
                        break;
                }
            }
            Position = _positionVector.ToPoint();
            if (Scene is GameScene gameScene && gameScene.BigBoss != null)
            {
                CheckCollision(gameScene);
            }
        }

        private void CheckCollision(GameScene scene)
        {
            var point = Position - scene.BigBoss.Position;
            var distance = Math.Abs(point.ToVector2().Length());
            if (distance < BigBoss.PhysicalRadius)
            {
                scene.BigBoss.Fail();
            }
        }

        private void NotifyFollower()
        {
            if (NextFollower != null)
            {
                var node = new NavigationNode
                {
                    Direction = CurrentDirection,
                };
                node.Trigger = Position;
                NextFollower.AddNavigationNode(node);
            }
        }
    }
}