using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Input;
using PhilExample.Interfaces;
using PhilExampleCrawler.Common.Interfaces;
using PhilExampleCrawler.Common.Models;
using Xamarin.Forms;

namespace PhilExample.VMs
{
    [QueryProperty(nameof(CategoryID), nameof(CategoryID))]
    internal class SelectCategoryVM : BaseVM, ICallbackPageVM<ICategory>
    {
        private int? _categoryID;
        public string CategoryID
        {
            get => _categoryID?.ToString() ?? null;
            set
            {
                _categoryID = string.IsNullOrEmpty(value) ? (int?)null : int.Parse(value);
            }
        }

        private readonly IPhExStorage _storage = DependencyService.Get<IPhExStorage>();
        private readonly IExamplePageService _ekaService = DependencyService.Get<IExamplePageService>();


        public event EventHandler<ICategory> OnPopped;
        public ICommand CloseCommand { get; }
        public ICommand GoToSubcategoryCommand { get; }
        public ICommand BackToCategoryCommand { get; }
        public ICommand SelectSubCategoryCommand { get; }


        private IEnumerable<Category> _categories;
        public List<CategoryMiniVM> Categories { get; } = new List<CategoryMiniVM>();
        public List<CategoryMiniVM> SubCategories { get; set; }
        public string[] AvailablePages { get; } = new string[] { "main", "sub" };
        private string _selectedPage = "main";
        public string SelectedPage { get => _selectedPage; set => SetProperty(ref _selectedPage, value); }
        bool _popupFinished = false;


        public SelectCategoryVM()
        {
            CloseCommand = new Command(async () => await CloseAsync());
            GoToSubcategoryCommand = new Command(GoToSubcategoryView);
            BackToCategoryCommand = new Command(BackToCategoryView);
            SelectSubCategoryCommand = new Command(SelectSubcategoryAsync);
        }

        public override async Task OnAppearingAsync()
        {
            _categories = await _storage.GetCategoriesAsync();

            foreach (var cat in _categories)
                Categories.Add(new CategoryMiniVM(cat, GoToSubcategoryCommand, cat.ID));

            if (_categoryID.HasValue)
            {
                //TODO: Preselect old selection?
            }
        }

        private void GoToSubcategoryView(object mainCatID)
        {
            var cat = _categories.FirstOrDefault(x => x.ID == (int)mainCatID);
            if (cat == null)
                return;

            SubCategories = cat.SubCategories.Select(x => new CategoryMiniVM(x, SelectSubCategoryCommand, x.ID,
                                                                            showArrow: false))
                                             .ToList();
            SubCategories.Insert(0, new CategoryMiniVM(cat, SelectSubCategoryCommand, cat.ID, showArrow: false));
            OnPropertyChanged(nameof(SubCategories));
            SelectedPage = "sub";
        }

        private async void SelectSubcategoryAsync(object subCatID)
        {
            if ((int)subCatID == -1)
            {
                OnPopped?.Invoke(this, _ekaService.GetDefaultCategory());
                await Shell.Current.GoToAsync("..");
                return;
            }

            IEnumerable<ICategory> iCats = _categories.Select(cat => cat as ICategory);
            IEnumerable<ICategory> iSubCats = _categories.SelectMany(cat => cat.SubCategories.Select(subCat => subCat as ICategory));
            IEnumerable<ICategory> allCats = iCats.Concat(iSubCats);

            ICategory selectedCat = allCats.FirstOrDefault(x => x.ID == (int)subCatID);
            if (selectedCat != null)
            {
                OnPopped?.Invoke(this, selectedCat);
                await Shell.Current.GoToAsync("..");
            }
        }

        private void BackToCategoryView()
        {
            SelectedPage = "main";
        }

        private async Task CloseAsync()
        {
            if (_popupFinished)
                return;
            _popupFinished = true;

            OnPopped?.Invoke(this, null);
            await Shell.Current.GoToAsync("..");
        }
    }

    public class CategoryPageTemplateSelector : DataTemplateSelector
    {
        public DataTemplate MainCategories { get; set; }
        public DataTemplate SubCategories { get; set; }

        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            return ((string)item) == "main" ? MainCategories : SubCategories;
        }
    }
}
