using PCUT.Extensions;
using PCUT.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;

namespace PCUT.Models
{
    public abstract class SelectableCollection : NotificationBase
    {
        protected readonly bool _withDefault;

        protected int _selectedIndex;
        public int SelectedIndex
        {
            get => _selectedIndex;
            set
            {
                if (_withDefault && value == 0)
                {
                    _selectedIndex = 0;
                }
                else
                {
                    SetProperty(ref _selectedIndex, value);
                }
            }
        }

        protected SelectableCollection(bool withDefault)
        {
            _withDefault = withDefault;
            _selectedIndex = -1;
        }

        private void Selector_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {
            var selector = sender as Selector;
            if (_withDefault && selector.SelectedIndex == 0)
            {
                selector.SelectedIndex = -1;
            }
        }

        public void Bind(Selector selector)
        {
            if (selector != null)
                selector.SelectionChanged += Selector_SelectionChanged;
        }
    }

    public class SelectableCollection<T> : SelectableCollection
    {
        private readonly T DefaultItem;

        private readonly List<T> _items;
        public ObservableCollection<T> Items { get; }
        public T SelectedItem => _selectedIndex >= 0 ? Items[_selectedIndex] : default;

        public SelectableCollection(T defaultItem) : base(true)
        {
            DefaultItem = defaultItem;
            _selectedIndex = -1;
            _items = new List<T>();
            Items = new ObservableCollection<T>();
        }

        public SelectableCollection(bool withDefault = false) : base(withDefault)
        {
            if (withDefault)
                DefaultItem = default;
            _selectedIndex = -1;
            _items = new List<T>();
            Items = new ObservableCollection<T>();
        }

        public SelectableCollection(params T[] items) : this()
        {
            AddRange(items);
        }

        public SelectableCollection(bool withDefault = false, params T[] items) : this(withDefault)
        {
            AddRange(items);
        }

        public SelectableCollection(T defaultItem, params T[] items) : this(defaultItem)
        {
            AddRange(items);
        }

        public void SelectBy(Func<T, bool> predicate)
        {
            var item = Items.FirstOrDefault(predicate);
            var index = (item == null) ? -1 : Items.IndexOf(item);
            SelectedIndex = index;
        }

        public void Load(IEnumerable<T> items)
        {
            SelectedIndex = -1;
            AddRange(items);
        }

        private void AddRange(IEnumerable<T> items)
        {
            _items.Clear();
            Items.Clear();
            if (_withDefault)
            {
                _items.Add(DefaultItem);
                Items.Add(DefaultItem);
            }
            foreach (var item in items)
            {
                _items.Add(item);
                Items.Add(item);
            }
        }

        public void Filter(Predicate<T> filter)
        {
            var start = _withDefault ? 1 : 0;
            Items.Filter(_items, filter, start);
        }
    }
}
