using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using UnityEngine;
using UnityEngine.AI;
using VOID.Generic.Objects.Abstract;
using VOID.Generic.Objects.Unit.Actions;

namespace VOID.Generic.Objects.Unit
{
    [RequireComponent(typeof(Rigidbody))]
    [RequireComponent(typeof(CapsuleCollider))]
    [RequireComponent(typeof(NavMeshAgent))]
    public class UnitObject : AbstractObject
    {
        [Title("=== UnitObject properties ===")]
        public UnitObjectData unitData;
        public UnitObjectEvents unitEvents;
        public UnitObjectActionQueue unitActionQueue;
        public UnitObjectAnimator unitAnimator;
        public UnitObjectNavAgent unitNavAgent;
        public UnitObjectState unitState;
        public UnitObjectDataCalculator unitDataCalculator;
        public UnitObjectBackpack unitBackpack;
        public UnitObjectEquipment unitEquipment;
        public UnitObjectAbilityBook unitAbilityBook;
        public UnitObjectActionBar unitActionBar;
        public UnitObjectAttitude unitAttitude;
        public UnitObjectSenses unitSenses;
        public UnitObjectLevel unitLevel;

        protected new void OnValidate()
        {
            base.OnValidate();
            GetComponent<CapsuleCollider>().hideFlags = HideFlags.NotEditable;
            GetComponent<NavMeshAgent>().hideFlags = HideFlags.NotEditable;
            GetComponent<NavMeshObstacle>().hideFlags = HideFlags.NotEditable;
            
            var unitCollider = GetComponent<CapsuleCollider>();
            unitCollider.isTrigger = true;
            unitCollider.includeLayers = LayerManager.Trigger | LayerManager.Dynamic;
            unitCollider.height = basicData.height;
            unitCollider.radius = basicData.radius;
            unitCollider.center = new Vector3(0f, basicData.height / 2f, 0f);
            
            // AGENT
            var navMeshAgent = GetComponent<NavMeshAgent>();
            navMeshAgent.speed = 2f;
            navMeshAgent.baseOffset = - 0.05f;
            navMeshAgent.angularSpeed = 1800f;
            navMeshAgent.acceleration = navMeshAgent.speed * 10;
            navMeshAgent.autoBraking = false;
            navMeshAgent.height = basicData.height;
            navMeshAgent.radius = basicData.radius;
            navMeshAgent.obstacleAvoidanceType = ObstacleAvoidanceType.NoObstacleAvoidance; 
            navMeshAgent.autoRepath = false;
            navMeshAgent.enabled = false;
            
            // IMPORTANT - custom link traverse (defined how unit will move through TraversableObject)
            navMeshAgent.autoTraverseOffMeshLink = false;
            
            var navMeshObstacle = GetComponent<NavMeshObstacle>();
            navMeshObstacle.shape = NavMeshObstacleShape.Capsule;
            navMeshObstacle.radius = basicData.radius;
            navMeshObstacle.height = basicData.radius;
            navMeshObstacle.center = Vector3.zero;
            navMeshObstacle.carving = true;
            navMeshObstacle.enabled = false;
        }
        
        protected override List<ObjectComponent> GetObjectComponents()
        {
            return base.GetObjectComponents()
                .Union(new List<ObjectComponent>
                {
                    unitData,
                    unitEvents,
                    unitActionQueue,
                    unitAnimator,
                    unitNavAgent,
                    unitState,
                    unitDataCalculator,
                    unitBackpack,
                    unitEquipment,
                    unitAbilityBook,
                    unitActionBar,
                    unitAttitude,
                    unitSenses,
                    unitLevel
                })
                .ToList();
        }

        public void OrderStop(bool stopCurrent = true, bool stopForced = false) => unitActionQueue.StopQueue(stopCurrent, stopForced);

        public void OrderInstantly(AbstractAction unitAction) => unitActionQueue.ExecuteInstantly(unitAction);

        public void Order(AbstractAction unitAction) => unitActionQueue.AddAction(unitAction);
        
        public void OrderChain(List<AbstractAction> unitActions) => unitActionQueue.AddActionChain(unitActions);
    }
}