using System.Collections.Generic;
using System.Linq;
using InfinityPBR.ModularCharacterHelper;
using UnityEngine;
using UnityEngine.AI;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Abstract.Events;
using VOID.Generic.Objects.Unit.Events;

namespace VOID.Generic.Objects.Unit
{
    [System.Serializable]
    public class UnitObjectState : ObjectComponent<UnitObject>
    {
        #region Initialize

        protected override void SelfInitialize()
        {
            modularCharacter = parent.GetComponentInChildren<ModularCharacter>();
            parent.GetComponentsInChildren<ModularPart>().ToList().ForEach(modularCharacter.AttachPart);
        }

        protected override void EventInitialize()
        {
            // Turn events
            parent.basicEvents.onTurnQueueStart.AddListener(OnTurnStart);
            parent.basicEvents.onTurnQueueEnter.AddListener(OnTurnEnter);
            parent.basicEvents.onTurnQueueLeave.AddListener(OnTurnLeave);
            parent.basicEvents.onTurnSelfStart.AddListener(OnTurnSelfStart);
            parent.basicEvents.onTurnSelfEnd.AddListener(OnTurnSelfEnd);
            
            // Ability casting events
            parent.unitEvents.onStartCasting.AddListener(OnStartCasting);
            parent.unitEvents.onEndCasting.AddListener(OnEndCasting);
            parent.unitEvents.onStartAbilityAfter.AddListener(OnStartAbility);
            parent.unitEvents.onEndAbility.AddListener(OnEndAbility);
            
            // Death & Revive
            parent.basicEvents.onDeathAfter.AddListener(OnDeath);
            parent.basicEvents.onRevive.AddListener(OnRevive);
            
            // Opened & Closed by other unit
            parent.unitEvents.onOpenedByOtherUnit.AddListener(OnOpenedByOtherUnit);
            parent.unitEvents.onClosedByOtherUnit.AddListener(OnClosedByOtherUnit);
        }

        #endregion

        public bool isMoving;
        public bool isSelfTurn;
        public bool isControllable => !parent.basicState.isDead && !isTraversing && !isAbility && !isCasting;
        public bool isTraversing;
        public bool isAbility;
        public bool isCasting;
        public List<UnitObject> openedBy { get; private set; } = new();
        public ModularCharacter modularCharacter { get; private set; }
        
        private void OnTurnStart(TurnEvent turnEvent)
        {
            RestoreTurnResources();
        }

        private void OnTurnEnter(TurnEvent turnEvent)
        {
            parent.OrderStop();
            RestoreTurnResources();
            parent.GetComponent<NavMeshObstacle>().enabled = true;
            isSelfTurn = false;
        }

        private void OnTurnLeave(TurnEvent turnEvent)
        {
            RestoreTurnResources();
            parent.GetComponent<NavMeshObstacle>().enabled = false;
        }

        private void OnTurnSelfStart(TurnEvent turnEvent)
        {
            isSelfTurn = true;
            parent.GetComponent<NavMeshObstacle>().enabled = false;
        }

        private void OnTurnSelfEnd(TurnEvent turnEvent)
        {
            isSelfTurn = false;
            parent.GetComponent<NavMeshObstacle>().enabled = true;
        }

        private void OnStartCasting(CastingEvent castingEvent) => isCasting = true;
        private void OnEndCasting(CastingEvent castingEvent) => isCasting = false;

        private void OnStartAbility(AbilityCastEvent abilityCastEvent) => isAbility = true;
        private void OnEndAbility(AbilityCastEvent abilityCastEvent) => isAbility = false;

        private void RestoreTurnResources()
        {
            var maxResources = parent.unitData.maxResources;
            parent.unitData.SetResource(UnitResourceType.ActionPoints, maxResources.actionPoints);
            parent.unitData.SetResource(UnitResourceType.MovePoints, maxResources.movePoints);
        }

        private void OnDeath(DeathEvent deathEvent)
        {
            parent.OrderStop();
            var collider = parent.GetComponent<CapsuleCollider>();
            collider.height = parent.basicData.radius;
            collider.center = new Vector3(0, parent.basicData.radius / 2, 0);
        }

        private void OnRevive(ReviveEvent reviveEvent)
        {
            var collider = parent.GetComponent<CapsuleCollider>();
            collider.height = parent.basicData.height;
            collider.center = new Vector3(0, parent.basicData.height / 2, 0);
        }  

        private void OnOpenedByOtherUnit(OpenOtherUnitEvent openOtherUnitEvent)
        {
            openedBy.Add(openOtherUnitEvent.openedBy);
        }

        private void OnClosedByOtherUnit(CloseOtherUnitEvent closeOtherUnitEvent)
        {
            openedBy.Remove(closeOtherUnitEvent.closedBy);
        }
    }
}