#nullable enable


namespace TagFighter.Effects.Steps
{
    using System.Linq;
    using System.Reflection;
    using System.Collections.Generic;

    [StepType(StepTypeAttribute.SetterStep)]
    public class PawnResourceSet : OutputStep<bool>
    {
        [UnityEngine.SerializeField]
        SinglePort<IEnumerable<double>> _in = new();

        [CareBoo.Serially.TypeFilter(derivedFrom: typeof(Resources.Resource<>))]
        public CareBoo.Serially.SerializableType? Resource;

        public override IEnumerable<IPort> Inputs {
            get {
                yield return _in;
            }
        }

        public override string ToString() {
            var resourceName = Resource == null || Resource.Type == null ? "*" : Resource.Type.Name;
            var statName = "Current";

            return $"Pawn.Set.{resourceName}.{statName}";
        }

        public override bool IsValid {
            get {
                return Resource != null && Resource.Type != null;
            }
        }

        public override bool Run(EffectInput blackBoard) {
            if (!IsValid || Resource == null) {
                UnityEngine.Debug.LogError($"{this} Inner types are null");
                return false;
            }
            var getSpecificMethod = typeof(PawnResourceSet).GetMethod(nameof(SetSpecific), BindingFlags.NonPublic | BindingFlags.Instance).
                                            MakeGenericMethod(Resource.Type, Resource.Type.BaseType.GetGenericArguments()[0]);
            var value = getSpecificMethod.Invoke(this, new object[] { blackBoard });

            return (bool)value;

        }
        bool SetSpecific<TResource, TUnitType>(EffectInput Data)
            where TResource : Resources.Resource<TUnitType>
            where TUnitType : Resources.IUnitType {

            var success = false;
            if (_in.Node != null) {
                var result = _in.Node.Run(Data);
                UnityEngine.Debug.Log($"{nameof(PawnResourceSet)} result {string.Join(",", result)}");
                var set = result.Zip(Data.Affected.Select(transform => transform.GetComponent<TResource>()), (value, resource) => (value, resource));
                foreach (var (value, resource) in set) {
                    Data.StatAccessor.AddCurrentModifier(resource, (Resources.Unit<TUnitType>)value);
                }
                success = true;
            }

            return success;
        }
        public override EffectStepNodeData ToData() {
            var effectStepNodeData = base.ToData();
            effectStepNodeData.Resource = Resource;
            // effectStepNodeData.Register = Register;
            return effectStepNodeData;
        }

        public override bool FromData(EffectStepNodeData effectStepNodeData, Dictionary<string, EffectStepNode> guidToNode) {
            base.FromData(effectStepNodeData, guidToNode);
            Resource = effectStepNodeData.Resource;
            // Register = effectStepNodeData.Register;
            return true;
        }

    }
}