using System;
using System.Collections;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Input;
using InABox.Core;
using InABox.Mobile.Shared;
using Syncfusion.Data.Extensions;
using Syncfusion.SfDataGrid.XForms;
using Xamarin.Forms;
using Xamarin.Forms.Xaml;

namespace InABox.Mobile
{

    public enum MobileGridSelectionMode
    {
        None,
        Single,
        Multiple
    }

    public class PullToRefreshCommand : ICommand
    {
    
        private readonly MobileGrid _grid;
        
        public bool CanExecute(object parameter)
        {
            return _grid.PullToRefresh;
        }
    
        public void Execute(object parameter)
        {
            _grid.RequestRefresh();
        }
    
        public event EventHandler CanExecuteChanged;
    
        public PullToRefreshCommand(MobileGrid grid)
        {
            _grid = grid;
        }
    }

    public class MobileGridSelectionArgs : EventArgs
    {
        public object[] Selection { get; private set; }

        public MobileGridSelectionArgs(object[] selection)
        {
            Selection = selection;
        }
    }
        
    public delegate void MobileGridSelectionChanged(object sender, MobileGridSelectionArgs args);
    
    public class MobileGridRefreshRequestArgs : EventArgs { }
    
    public delegate void MobileGridRefreshRequested(object sender, MobileGridRefreshRequestArgs args);
    
    [XamlCompilation(XamlCompilationOptions.Compile)]
    public partial class MobileGrid
    {

        public MobileGridColumns Columns { get; private set; }
        
        public object ItemsSource
        {
            get => Grid.ItemsSource;
            set
            {
                Grid.ItemsSource = value;
                UpdateSummaryRow();
            }
        }

        public object[] SelectedItems => Grid.SelectedItems.ToArray();

        private bool _canSearch = true;
        public bool CanSearch 
        { 
            get => _canSearch;
            set
            {
                _canSearch = value;
                CheckSearchVisibility();
            }
        }
        
        public static readonly BindableProperty PullToRefreshProperty = BindableProperty.Create(
            nameof(PullToRefresh), 
            typeof(bool), 
            typeof(MobileGrid));

        public bool PullToRefresh
        {
            get => (bool)GetValue(PullToRefreshProperty);
            set
            {
                SetValue(PullToRefreshProperty, value);
                UpdateSummaryRow();
            }
        }

        public static readonly BindableProperty LastUpdatedProperty = BindableProperty.Create(
            nameof(LastUpdated), 
            typeof(DateTime), 
            typeof(MobileGrid));
        
        public DateTime LastUpdated
        {
            get => (DateTime)GetValue(LastUpdatedProperty);
            set
            {
                SetValue(LastUpdatedProperty,value);
                UpdateSummaryRow();
            }
        }
        
        public static readonly BindableProperty ShowRecordCountProperty = BindableProperty.Create(
            nameof(ShowRecordCount), 
            typeof(bool), 
            typeof(MobileGrid), 
            false);

        public bool ShowRecordCount
        {
            get => (bool)GetValue(ShowRecordCountProperty);
            set
            {
                SetValue(ShowRecordCountProperty,value);
                UpdateSummaryRow();
            }
        }

        private void UpdateSummaryRow()
        {
            _lastupdate.IsVisible = !LastUpdated.IsEmpty();
            _lastupdate.Text = $"{DateTimeToAgeConverter.FormatTime(LastUpdated)}";
            _pulltorefresh.IsVisible = PullToRefresh;
            _numrecords.Text = $"{(ItemsSource as IEnumerable)?.ToList<object>().Count() ?? 0} records";
            _numrecords.IsVisible = ShowRecordCount && (ItemsSource is IEnumerable);
            _refreshgrid.IsVisible = _lastupdate.IsVisible || _pulltorefresh.IsVisible || _numrecords.IsVisible;
        }
        
        public MobileGridSelectionMode SelectionMode
        {
            
            get => Grid.SelectionMode == Syncfusion.SfDataGrid.XForms.SelectionMode.Multiple
                ? MobileGridSelectionMode.Multiple
                : Grid.SelectionMode == Syncfusion.SfDataGrid.XForms.SelectionMode.Single
                    ? MobileGridSelectionMode.Single
                    : MobileGridSelectionMode.None;
            
            set => Grid.SelectionMode = value == MobileGridSelectionMode.Multiple
                ? Syncfusion.SfDataGrid.XForms.SelectionMode.Multiple
                : value == MobileGridSelectionMode.Single 
                    ? Syncfusion.SfDataGrid.XForms.SelectionMode.SingleDeselect
                    : Syncfusion.SfDataGrid.XForms.SelectionMode.None;
        }

        public event MobileGridSelectionChanged SelectionChanged;
        
        public event MobileGridRefreshRequested RefreshRequested;

        internal void RequestRefresh()
        {
            var src = ItemsSource;
            ItemsSource = null;
            RefreshRequested?.Invoke(this, new MobileGridRefreshRequestArgs());
            ItemsSource = src;
        }

        private String _searchText = "";
        
        bool DoSearch(object data)
        {
            if (String.IsNullOrWhiteSpace(_searchText))
                return true;

            foreach (var col in Grid.Columns)
            {
                var property = data.GetType().GetProperty(col.MappingName);
                if (property != null && property.PropertyType != typeof(ImageSource))
                {
                    var value = property.GetValue(data);
                    var sValue = String.IsNullOrWhiteSpace(col.Format)
                        ? value?.ToString() ?? string.Empty
                        : String.Format($"{{0:{col.Format}}}", value);
                    if (sValue.ToUpper().Contains(_searchText))
                        return true;
                }
            }
            return false;
        }

        public double RowHeight
        {
            get => Grid.RowHeight;
            set => Grid.RowHeight = value;
        }

        public void ClearSelection()
        {
            Grid.SelectedItem = null;
            Grid.SelectedItems.Clear();
        }
        
        public MobileGrid()
        {
            InitializeComponent();
            Columns = new MobileGridColumns(Grid);
            Columns.Changed += (sender, args) => CheckSearchVisibility(); 
            SelectionMode = MobileGridSelectionMode.Single;
            CanSearch = true;
            Grid.PullToRefreshCommand = new PullToRefreshCommand(this);
            Grid.QueryCellStyle += (sender, args) =>
            {
                args.Style.FontSize = Device.GetNamedSize(NamedSize.Micro, typeof(Label));
            };
        }
        
        private void Search_OnTextChanged(object sender, MobileSearchBarTextChangedArgs args)
        {
            _searchText = args.Text?.ToUpper() ?? string.Empty;
            Grid.View.Filter = DoSearch;
            Grid.View.RefreshFilter(true);
            UpdateSummaryRow();
        }

        private void Grid_OnGridViewCreated(object sender, GridViewCreatedEventArgs e)
        {
            CheckSearchVisibility();
        }

        private void CheckSearchVisibility()
        {
            var searchables = Grid.Columns.Any(x=>(x is GridImageColumn) == false);
            Search.IsVisible = searchables && CanSearch;
            // if (Grid.View != null)
            // {
            //     if (Search.IsVisible)
            //         Grid.View.Filter = DoSearch;
            //     else
            //         Grid.View.Filter = null;
            // }
        }

        private void Grid_OnSelectionChanged(object sender, GridSelectionChangedEventArgs e)
        {
            //SelectionChanged?.Invoke(this, new MobileGridSelectionArgs(Grid.SelectedItems.ToArray()));
        }

        private void Grid_OnGridTapped(object sender, GridTappedEventArgs e)
        {
            if (SelectionMode == MobileGridSelectionMode.Multiple)
                return;
            var column = Columns[e.RowColumnIndex.ColumnIndex];
            if (column.Tapped != null)
                column.Tapped?.Invoke(column, e.RowData);
            else
                SelectionChanged?.Invoke(this, new MobileGridSelectionArgs(new [] { e.RowData }));
            
        }
        
        // private void SfPullToRefresh_OnRefreshing(object sender, EventArgs e)
        // {
        //     pullToRefresh.IsRefreshing = true;
        //     var _items = ItemsSource;
        //     ItemsSource = null;
        //     RefreshRequested?.Invoke(this, new MobileGridRefreshRequestArgs());
        //     pullToRefresh.IsRefreshing = false;
        //     ItemsSource = _items;
        // }
        
    }
}