using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Beam.Abstractions;
using Beam.Dynamic;
using Beam.Models;

namespace Beam {
    //public delegate string LinkGenerator(params object[] ps);
    //public delegate object Incrementor(object obj, int amount);

    public class OrderedLinkGenerator : IEnumerator<string?> {
        public ILinkBuilder Builder { get; set; }
        public IStateChangeBehaviour Behaviour { get; }
        
        private IState? EndState;
        private IState InitialState;

        public OrderedLinkGenerator(ILinkBuilder builder, IStateChangeBehaviour behaviour, params string[] initialState) 
            : this(builder, behaviour, new State(initialState)) { }
        public OrderedLinkGenerator(ILinkBuilder builder, IStateChangeBehaviour behaviour, IState initialState, IState? endState = null) {
            Builder = builder;
            Behaviour = behaviour;
            InitialState = initialState.Copy();
            EndState = endState?.Copy();
            State = InitialState.Copy();

            Reset();
        }

        public IState State { get; set; }
        public string? Current { get; private set; }

        object? IEnumerator.Current => Current;

        public void Dispose() {
            GC.SuppressFinalize(this);
            return;
        }

        public bool MoveNext() {
            if (string.IsNullOrWhiteSpace(Current) || (EndState is not null && State.GetState().SequenceEqual(EndState.GetState()))) {
                Current = null;
                return false;
            }
            
            Behaviour.Apply(State, 1);
            Current = Builder.Build(State.AsReadOnly());
            
            return !string.IsNullOrWhiteSpace(Current) && (EndState is null || !State.GetState().SequenceEqual(EndState.GetState()));
        }

        public void Reset() {
            State = InitialState.Copy();
            Behaviour.Apply(State, -1);
            Current = Builder.Build(State.AsReadOnly());
        }
    }
}
