using System;
using System.Collections.Generic;
using System.Linq;
using Sirenix.Utilities;
using VOID.Generic.Dict;
using VOID.Generic.Objects.Unit.Events;
using VOID.Generic.Status.Effect;

namespace VOID.Generic.Objects.Unit.DataCalculator
{
    public class MainAttributeCalcGroup : ICalcGroup
    {
        public string GetMarkerGroup()
        {
            return "MainAttribute";
        }

        public IEnumerable<string> GetMarkerItems()
        {
            return GetEnums().Select(@enum => @enum.ToString());
        }

        public Type GetEnumType()
        {
            return typeof(MainAttributeType);
        }

        public IEnumerable<Enum> GetEnums()
        {
            return Enum.GetValues(GetEnumType()).OfType<Enum>();
        }

        public Enum GetEnum(string markerItem)
        {
            return Enum.Parse<MainAttributeType>(markerItem, true);
        }

        public float GetEffectValue(UnitObject unit, string markerItem)
        {
            var @enum = Enum.Parse<MainAttributeType>(markerItem, true);
            return unit.statusManager.GetStatuses()
                .SelectMany(status => status.effects)
                .FilterCast<PointChangeMainAttributeEffect>()
                .Where(effect => effect.mainAttributeType == @enum)
                .Select(effect => effect.pointModificator)
                .Sum();
        }

        public float GetBaseValue(UnitObject unit, string markerItem)
        {
            return unit.unitData.baseMainAttributes.Get(Enum.Parse<MainAttributeType>(markerItem, true));
        }

        public float GetValue(UnitObject unit, string markerItem)
        {
            return unit.unitData.mainAttributes.Get(Enum.Parse<MainAttributeType>(markerItem, true));
        }

        public void UpdateWithValue(UnitObject unit, string markerItem, float formulaValue)
        {
            var @enum = Enum.Parse<MainAttributeType>(markerItem, true);
            var baseValue = GetBaseValue(unit, markerItem);
            var effectValue = GetEffectValue(unit, markerItem);
            var previousValue = GetValue(unit, markerItem);
            var newValue = baseValue + effectValue + formulaValue;
            var diffValue = newValue - previousValue;
            unit.unitData.mainAttributes.Set(@enum, (int)newValue);

            unit.unitEvents.onMainAttributeChange.Invoke(
                new MainAttributeChangeEvent
                {
                    unit = unit,
                    type = @enum,
                    changedValue = (int)diffValue,
                    newValue = (int)newValue,
                    oldValue = (int)previousValue
                }
            );
        }
    }
}