namespace BakaIterator
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
 
    public class BakaIterator<T> 
    {
        public T Current => _items[_index];
        public bool HasNext => _index + 1 < _items.Count - 1;
        public int Position => _index;
        public int Count => _items.Count;
        public BakaIterator(IList<T> items)
        {
            if (items is null)
            {
                throw new ArgumentNullException(nameof(items));
            }
            if (items.Count == 0)
            {
                throw new ArgumentException("Items must contain at least 1 element", nameof(items));
            }
            _items = items;
            _index = 0;
        }
 
        private readonly IList<T> _items;
        private int _index;
        public BakaIterator<T> MoveForward(int steps = 1)
        {
            if (steps < 0)
            {
                throw new ArgumentException("Invalid steps count. Must be 0 or positiv integer");
            }
            if (_index + steps > _items.Count - 1)
            {
                throw new IndexOutOfRangeException("To many steps");
            }
            _index += steps;
            return this;
        }
        public BakaIterator<T> MoveBackwards(int steps = 1)
        {
            if (steps < 0)
            {
                throw new ArgumentException("Invalid steps count. Must be 0 or positiv integer");
            }
            if (_index - steps < 0)
            {
                throw new IndexOutOfRangeException("To many steps");
            }
            _index -= steps;
            return this;
        }
        public BakaIterator<T> Reset()
        {
            _index = 0;
            return this;
        }
 
        public BakaIterator<T> First(Func<T, bool> predicate, bool throwIfNotFound = true)
        {
            do
            {
                if (predicate(Current))//Мы уже получили этот элемент
                {
                    return this;
                }
 
                if (HasNext)
                {
                    MoveForward();
                }
            } while (HasNext);
 
            if (throwIfNotFound)
            {
                throw new Exception("Item not found");
            }
            return this;
        }
        //Для случая если нам нужен не просто первый, но первый который не текущий
        public BakaIterator<T> FirstNext(Func<T, bool> predicate, bool throwIfNotFound = true)
        {
            return First((x) => predicate(x) && Current.Equals(x) == false, throwIfNotFound);
        }
 
        public BakaIterator<T> ThrowIf(Func<T, bool> predicate)
        {
            if (predicate(Current))
            {
                throw new Exception($"Item {Current} is ");
            }
            return this;
        }
        public BakaIterator<T> ThrowIfNot(Func<T, bool> predicate)
        {
            if (!predicate(Current))
            {
                throw new Exception("Current item is not");
            }
            return this;
        }
 
        public BakaIterator<T> ForEachFromCurrent(Action<T> action)
        {
            foreach(var i in _items.Skip(_index + 1))
            {
                action(i);
            }
            return this;
        }
        public BakaIterator<T> ForEach(Action<T> action)
        {
            foreach (var i in _items)
            {
                action(i);
            }
            return this;
        }
    }
}