using System;
using System.Collections.Generic;
using System.Linq;

#nullable enable
namespace Aurora.Cursor
{
    public enum SortDirection
    {
        Asc,
        Desc,
    }

    public class Cursor<T> where T : ICursorObject
    {
        private CursorList<T> _list;

        private string? _previousPageToken;
        private string? _nextPageToken;
        private int _pageSize;
        private Func<KeyValuePair<string, T>, string> _sortDelgate;
        private SortDirection _direction;
        public Cursor(ref CursorList<T> list)
        {
            this._list = list;
            this._previousPageToken = string.Empty;
            this._nextPageToken = string.Empty;
            this._pageSize = 10;
            this._sortDelgate = delegate (KeyValuePair<string, T> item)
            {
                return item.Value.Id;
            };
        }

        public CursorResult<T> GetNextPage()
        {
            List<KeyValuePair<string, T>> tmpList;

            // Sort reference list
            if (this._direction == SortDirection.Desc)
            {
                tmpList = this._list.OrderByDescending(this._sortDelgate).ToList();

            }
            else
            {
                tmpList = this._list.OrderBy(this._sortDelgate).ToList();
            }

            if (tmpList == null)
            {
                throw new System.NullReferenceException();
            }

            int startIdx = 0;
            if (!string.IsNullOrEmpty(this._nextPageToken))
            {
                // TODO find another way to index into the list that's not a regular array search
                startIdx = tmpList.FindIndex(item => item.Key == this._nextPageToken);
            }

            int endIdx = startIdx + this._pageSize;

            List<T> selection = new List<T>();

            // Get page
            for (int i = startIdx; i < tmpList.Count && i < endIdx; i++)
            {
                selection.Add(tmpList.ElementAt(i).Value);
            }

            return new CursorResult<T>
            {
                NextPageToken = selection[selection.Count - 1].Id,
                PrevPageToken = selection[0].Id,
                Count = this._list.Count,
                Result = selection
            };
        }

        public CursorResult<T> GetPreviousPage()
        {
            throw new NotImplementedException();
        }

        public Cursor<T> WithNextPage(string nextPageToken)
        {
            this._nextPageToken = nextPageToken;
            return this;
        }

        public Cursor<T> WithPreviousPage(string prevPageToken)
        {
            this._previousPageToken = prevPageToken;
            return this;
        }

        public Cursor<T> WithSort(Func<KeyValuePair<string, T>, string> sortDelegate, SortDirection direction)
        {
            this._sortDelgate = sortDelegate;
            this._direction = direction;
            return this;
        }

        public Cursor<T> WithSize(int size)
        {
            this._pageSize = size;
            return this;
        }
    }

}