using inutralia.Models;
using inutralia.Views;
using System.Threading.Tasks;
using MvvmHelpers;    // Este namespace está en el paquete Refractored.MvvmHelpers
using Xamarin.Forms;
using System;

namespace inutralia.ViewModels
{
    /// <summary>
    /// ViewModel de un menú semanal
    /// </summary>
	public abstract class MenuBaseViewModel : ModelBasedViewModel
	{
		public MenuBaseViewModel ( MenuBase menu) : base (menu)
		{
            Title = WeekMenu?.Title;
		}

        #region Properties

        /// <summary>
        /// El menú semanal mostrado
        /// </summary>
        public virtual MenuBase WeekMenu => Model as MenuBase;

        /// <summary>
        /// Backup variable para el índice del día seleccionado
        /// </summary>
        protected int _Index = -1;

        /// <summary>
        /// Índice del día seleccionado
        /// </summary>
        public int Index
        {
            get { return _Index; }
            set
            {
                if( (_Index != value) && (value >= 0) && (value < WeekMenu?.Days?.Count) )
                {
                    _Index = value;
                    OnPropertyChanged ("Index");
                    OnPropertyChanged ("CurrentDay");

                    OnIndexChanged ();
                } //endif
            }
        }

        /// <summary>
        /// Retorna el día seleccionado
        /// </summary>
        public Day CurrentDay
        {
            get
            {
                return ( (Index >= 0) && (Index < WeekMenu?.Days?.Count) ) ? WeekMenu.Days [Index] : null;
            }
        }

        protected bool _LoadingRecipes = false;

        /// <summary>
        /// Indica si se están cargando recetas
        /// </summary>
        public bool IsLoadingRecipes
        {
            get { return _LoadingRecipes; }
            set
            {
                SetProperty (ref _LoadingRecipes, value, "IsLoadingRecipes");
                OnPropertyChanged ("IsNotLoadingRecipes");
            }
        }

        /// <summary>
        /// Indica si no se están cargando recetas
        /// </summary>
        public bool IsNotLoadingRecipes
        {
            get { return !_LoadingRecipes; }
            set
            {
                SetProperty (ref _LoadingRecipes, !value, "IsLoadingRecipes");
                OnPropertyChanged ("IsNotLoadingRecipes");
            }
        }

        #endregion

        #region Commands

        protected Command _ShowRecipeCommand = null;

        /// <summary>
        /// Comando para mostrar una receta
        /// </summary>
        public Command ShowRecipeCommand => _ShowRecipeCommand ?? 
            (_ShowRecipeCommand = new Command (async (parameter) => await ShowRecipe (parameter as Recipe)));

        protected Command _ShowRecomendationCommand = null;

        /// <summary>
        /// Comando para mostrar las recomendaciones
        /// </summary>
        public Command ShowRecomendationCommand => _ShowRecomendationCommand ??
            (_ShowRecomendationCommand = new Command (async () => await ShowRecomendation()));

        #endregion

        #region Tasks

        /// <summary>
        /// Actualiza los datos de todas las recetas
        /// </summary>
        public async Task LoadAllRecipesAsync ()
        {
            IsLoadingRecipes = true;

            // Obtener las recetas completas
            foreach (var d in WeekMenu.Days)
            {
                foreach (var r in d.LunchFirst)
                    await App.API.RefreshItemAsync (r);
                foreach (var r in d.LunchSecond)
                    await App.API.RefreshItemAsync (r);
                foreach (var r in d.DinnerFirst)
                    await App.API.RefreshItemAsync (r);
                foreach (var r in d.DinnerSecond)
                    await App.API.RefreshItemAsync (r);
            } //endforeach

            IsLoadingRecipes = false;
        }

        /// <summary>
        /// Navega a la vista de receta
        /// </summary>
        /// <param name="recipe">La receta a mostrar</param>
        protected async Task ShowRecipe(Recipe recipe)
        {
            await PushAsync (new RecipeDetailView () { BindingContext = new RecipeViewModel(recipe) });
        }

        /// <summary>
        /// Navega a la vista de recomendaciones
        /// </summary>
        protected async Task ShowRecomendation ()
        {
            await PushAsync (new RecomendationView () { BindingContext = WeekMenu });
        }

        #endregion

        /// <summary>
        /// Llamado cuando se han actualizado los datos
        /// </summary>
        protected override void OnDataRefreshed ()
        {
            base.OnDataRefreshed ();

            // Informar que ha cambiado el menú
            OnPropertyChanged ("WeekMenu");

            // Cambiar título
            Title = WeekMenu?.Title;

            // Si no tenemos un día seleccionado, seleccionar automáticamente 
            // el día de la semana en el que estemos
            if (Index < 0)
            {
                DayOfWeek dw = DateTime.Now.DayOfWeek;

                // Como DayOfWeek empieza con el 0 en Domingo, le "restamos 1 modulo 7"
                Index = ( (int) dw + 6) % 7;
            } //endif

            // Informar que ha cambiado el día actual (aunque no cambie el índice 
            // puede haber cambiado el contenido)
            OnPropertyChanged ("CurrentDay");
        }

        /// <summary>
        /// Llamado cuando ha cambiado el índice del día seleccionado
        /// </summary>
        protected virtual void OnIndexChanged ()
        {
        }
    }
}
