using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.OdinInspector;
using Sirenix.Utilities;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Abstract;
using VOID.Generic.Objects.Unit.AI;
using VOID.Generic.Objects.Unit.Events;

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

        protected override void SelfInitialize()
        {
            // Fill _unitsInSight with all enum keys
            Enum.GetValues(typeof(AttitudeType))
                .OfType<AttitudeType>()
                .ForEach(attitude => _unitsInSight.Add(attitude, new List<UnitObject>()));
        }

        protected override void EventInitialize()
        {
            parent.unitEvents.onSightEnter.AddListener(OnSightEnter);
            parent.unitEvents.onSightExit.AddListener(OnSightExit);
        }

        protected override void Initialize()
        {
            UnitSight.Create(parent);
            UnitHear.Create(parent);
        }

        #endregion

        [Title("Units & objects in sight")]
        private Dictionary<AttitudeType, List<UnitObject>> _unitsInSight = new();
        private List<AbstractObject> _objectsInSight = new();

        public List<UnitObject> GetUnitsInSightByAttitude(AttitudeType attitudeType)
        {
            return _unitsInSight[attitudeType];
        }

        public List<AbstractObject> GetObjectsInSight()
        {
            return _objectsInSight;
        }

        private void OnSightEnter(SenseSightEvent sightEvent)
        {
            if (sightEvent.sightObject is UnitObject otherUnit)
            {
                var attitude = parent.unitAttitude.GetAttitudeWith(otherUnit);
                _unitsInSight[attitude].Add(otherUnit);
            }
            else
            {
                _objectsInSight.Add(sightEvent.sightObject);
            }
        }

        private void OnSightExit(SenseSightEvent sightEvent)
        {
            if (sightEvent.sightObject is UnitObject otherUnit)
            {
                _unitsInSight.Values.ForEach(units => units.Remove(otherUnit));
            }

            _objectsInSight.Remove(sightEvent.sightObject);
        }
    }
}