#nullable enable


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

    [StepType(StepTypeAttribute.OperatorStep)]
    public class Zip : OutputStep<IEnumerable<double>>
    {
        [UnityEngine.SerializeField]
        MultiPort<IEnumerable<double>> _in = new();

        [UnityEngine.SerializeReference, ShowSerializeReference]
        public IResourceOperator? Operator;

        [UnityEngine.SerializeField]
        List<double> _const = new();

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

        public static IEnumerable<double> GetDefault(EffectInput blackBoard) {
            double defaultVal = 0;
            return blackBoard.Affected.Select(transform => defaultVal);
        }

        public override IEnumerable<double> Run(EffectInput blackBoard) {
            if (!IsValid || Operator == null) {
                UnityEngine.Debug.LogError($"{this} Inner types are null");
                return GetDefault(blackBoard);
            }
            return _in.Nodes.Select(getter => getter.Run(blackBoard)).Concat(_const.Select(value => blackBoard.Affected.Select(transform => value)))
                        .DefaultIfEmpty(GetDefault(blackBoard))
                        .Aggregate((current, next) =>
                        current.Zip(next, (first, second) =>
                        Operator.Operate(first, second)));
        }

        public override string ToString() {
            var operatorName = Operator == null ? "*" : Operator.GetType().Name;
            var constName = _const.Count == 0 ? "" : $"({string.Join(",", _const.Select(val => $"{val}[]"))})";

            return $"Zip.{operatorName}{constName}";
        }

        public override bool IsValid => Operator != null;

        public override EffectStepNodeData ToData() {
            var effectStepNodeData = base.ToData();
            effectStepNodeData.Const = _const;
            effectStepNodeData.Operator = Operator;
            return effectStepNodeData;
        }

        public override bool FromData(EffectStepNodeData effectStepNodeData, Dictionary<string, EffectStepNode> guidToNode) {
            base.FromData(effectStepNodeData, guidToNode);
            _const = effectStepNodeData.Const ?? new();
            Operator = effectStepNodeData.Operator;
            return true;
        }
    }

}