using Billing.Themes;
using System;
using Xamarin.Forms;

namespace Billing.UI
{
    public enum BorderStyle
    {
        None = 0,
        RoundedRect
    }

    public class OptionEntry : Entry { }
    public class OptionEditor : Editor { }
    public class OptionPicker : Picker
    {
        public static readonly BindableProperty BorderStyleProperty = Helper.Create<BorderStyle, OptionPicker>(nameof(BorderStyle));

        public BorderStyle BorderStyle
        {
            get => (BorderStyle)GetValue(BorderStyleProperty);
            set => SetValue(BorderStyleProperty, value);
        }
    }
    public class OptionDatePicker : DatePicker { }
    public class OptionTimePicker : TimePicker { }

    public abstract class OptionCell : ViewCell
    {
        public static readonly BindableProperty TitleProperty = Helper.Create<string, OptionCell>(nameof(Title));
        public static readonly BindableProperty BackgroundColorProperty = Helper.Create<Color, OptionCell>(nameof(BackgroundColor));
        public static readonly BindableProperty IconProperty = Helper.Create<ImageSource, OptionCell>(nameof(Icon));

        public string Title
        {
            get => (string)GetValue(TitleProperty);
            set => SetValue(TitleProperty, value);
        }
        public Color BackgroundColor
        {
            get => (Color)GetValue(BackgroundColorProperty);
            set => SetValue(BackgroundColorProperty, value);
        }
        [TypeConverter(typeof(ImageSourceConverter))]
        public ImageSource Icon
        {
            get => (ImageSource)GetValue(IconProperty);
            set => SetValue(IconProperty, value);
        }

        protected abstract View Content { get; }

        public OptionCell()
        {
            View = new Grid
            {
                BindingContext = this,
                Padding = new Thickness(20, 0),
                ColumnDefinitions =
                {
                    new ColumnDefinition { Width = GridLength.Auto },
                    new ColumnDefinition { Width = new GridLength(.35, GridUnitType.Star) },
                    new ColumnDefinition { Width = new GridLength(.65, GridUnitType.Star) }
                },
                Children =
                {
                    new TintImage
                    {
                        WidthRequest = 20,
                        HeightRequest = 20,
                        Aspect = Aspect.AspectFit,
                        VerticalOptions = LayoutOptions.Center,
                        Margin = new Thickness(6, 0)
                    }
                    .Binding(VisualElement.IsVisibleProperty, nameof(Icon), converter: new NotNullConverter())
                    .Binding(Image.SourceProperty, nameof(Icon)),

                    new Label
                    {
                        LineBreakMode = LineBreakMode.TailTruncation,
                        VerticalOptions = LayoutOptions.Center
                    }
                    .GridColumn(1)
                    .Binding(Label.TextProperty, nameof(Title))
                    .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor),

                    Content.GridColumn(2)
                }
            }
            .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
        }
    }

    public abstract class OptionVerticalCell : OptionCell
    {
        public OptionVerticalCell()
        {
            View = new Grid
            {
                BindingContext = this,
                Padding = new Thickness(20, 0),
                ColumnDefinitions =
                {
                    new ColumnDefinition { Width = GridLength.Auto },
                    new ColumnDefinition { Width = GridLength.Star }
                },
                RowDefinitions =
                {
                    new RowDefinition { Height = new GridLength(40) },
                    new RowDefinition { Height = GridLength.Star }
                },
                Children =
                {
                    new TintImage
                    {
                        WidthRequest = 20,
                        HeightRequest = 20,
                        Aspect = Aspect.AspectFit,
                        VerticalOptions = LayoutOptions.Center,
                        Margin = new Thickness(6, 0)
                    }
                    .Binding(VisualElement.IsVisibleProperty, nameof(Icon), converter: new NotNullConverter())
                    .Binding(Image.SourceProperty, nameof(Icon)),

                    new Label
                    {
                        LineBreakMode = LineBreakMode.TailTruncation,
                        VerticalOptions = LayoutOptions.Center
                    }
                    .GridColumn(1)
                    .Binding(Label.TextProperty, nameof(Title))
                    .DynamicResource(Label.TextColorProperty, BaseTheme.TextColor),

                    Content.GridRow(1).GridColumnSpan(2)
                }
            }
            .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
        }
    }

    public class OptionTextCell : OptionCell
    {
        public static readonly BindableProperty DetailProperty = Helper.Create<string, OptionTextCell>(nameof(Detail));

        public string Detail
        {
            get => (string)GetValue(DetailProperty);
            set => SetValue(DetailProperty, value);
        }

        protected override View Content => new Label
        {
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.Center
        }
        .Binding(Label.TextProperty, nameof(Detail))
        .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor);
    }

    public class OptionSelectCell : OptionTextCell
    {
        public static readonly BindableProperty CommandProperty = Helper.Create<Command, OptionSelectCell>(nameof(Command));
        public static readonly BindableProperty CommandParameterProperty = Helper.Create<object, OptionSelectCell>(nameof(CommandParameter));

        public Command Command
        {
            get => (Command)GetValue(CommandProperty);
            set => SetValue(CommandProperty, value);
        }
        public object CommandParameter
        {
            get => GetValue(CommandParameterProperty);
            set => SetValue(CommandParameterProperty, value);
        }

        protected override View Content => new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.End,
            Children =
            {
                new Label
                {
                    VerticalOptions = LayoutOptions.Center
                }
                .Binding(Label.TextProperty, nameof(Detail))
                .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor),

                new TintImage
                {
                    HeightRequest = 20,
                    VerticalOptions = LayoutOptions.Center,
                    Margin = new Thickness(6, 0),
                    Source = "right.png"
                }
            },
            GestureRecognizers =
            {
                new TapGestureRecognizer()
                    .Binding(TapGestureRecognizer.CommandProperty, nameof(Command))
                    .Binding(TapGestureRecognizer.CommandParameterProperty, nameof(CommandParameter))
            }
        };
    }

    public class OptionImageCell : OptionSelectCell
    {
        public static readonly BindableProperty ImageSourceProperty = Helper.Create<ImageSource, OptionImageCell>(nameof(ImageSource));
        public static readonly BindableProperty TintColorProperty = Helper.Create<Color?, OptionImageCell>(nameof(TintColor));

        [TypeConverter(typeof(ImageSourceConverter))]
        public ImageSource ImageSource
        {
            get => (ImageSource)GetValue(ImageSourceProperty);
            set => SetValue(ImageSourceProperty, value);
        }
        [TypeConverter(typeof(ColorTypeConverter))]
        public Color? TintColor
        {
            get => (Color?)GetValue(TintColorProperty);
            set => SetValue(TintColorProperty, value);
        }

        protected override View Content => new StackLayout
        {
            Orientation = StackOrientation.Horizontal,
            HorizontalOptions = LayoutOptions.End,
            Children =
            {
                new TintImage
                {
                    WidthRequest = 26,
                    HeightRequest = 20,
                    VerticalOptions = LayoutOptions.Center,
                    Margin = new Thickness(6, 0)
                }
                .Binding(Image.SourceProperty, nameof(ImageSource))
                .Binding(TintHelper.TintColorProperty, nameof(TintColor)),

                new Label
                {
                    VerticalOptions = LayoutOptions.Center
                }
                .Binding(Label.TextProperty, nameof(Detail))
                .DynamicResource(Label.TextColorProperty, BaseTheme.SecondaryTextColor),

                new TintImage
                {
                    HeightRequest = 20,
                    VerticalOptions = LayoutOptions.Center,
                    Margin = new Thickness(6, 0),
                    Source = "right.png"
                }
            },
            GestureRecognizers =
            {
                new TapGestureRecognizer()
                    .Binding(TapGestureRecognizer.CommandProperty, nameof(Command))
                    .Binding(TapGestureRecognizer.CommandParameterProperty, nameof(CommandParameter))
            }
        };
    }

    public class OptionSwitchCell : OptionCell
    {
        public static readonly BindableProperty IsToggledProperty = Helper.Create<bool, OptionSwitchCell>(nameof(IsToggled));

        public bool IsToggled
        {
            get => (bool)GetValue(IsToggledProperty);
            set => SetValue(IsToggledProperty, value);
        }

        protected override View Content => new Switch
        {
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.Center
        }
        .Binding(Switch.IsToggledProperty, nameof(IsToggled), mode: BindingMode.TwoWay);
    }

    public class OptionDatePickerCell : OptionCell
    {
        public static readonly BindableProperty DateProperty = Helper.Create<DateTime, OptionDatePickerCell>(nameof(Date));

        public DateTime Date
        {
            get => (DateTime)GetValue(DateProperty);
            set => SetValue(DateProperty, value);
        }

        protected override View Content => new OptionDatePicker
        {
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.Fill
        }
        .Binding(DatePicker.DateProperty, nameof(Date), mode: BindingMode.TwoWay)
        .DynamicResource(DatePicker.TextColorProperty, BaseTheme.TextColor)
        .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
    }

    public class OptionTimePickerCell : OptionCell
    {
        public static readonly BindableProperty TimeProperty = Helper.Create<TimeSpan, OptionTimePickerCell>(nameof(Time));

        public TimeSpan Time
        {
            get => (TimeSpan)GetValue(TimeProperty);
            set => SetValue(TimeProperty, value);
        }

        protected override View Content => new OptionTimePicker
        {
            HorizontalOptions = LayoutOptions.End,
            VerticalOptions = LayoutOptions.Fill
        }
        .Binding(TimePicker.TimeProperty, nameof(Time), mode: BindingMode.TwoWay)
        .DynamicResource(TimePicker.TextColorProperty, BaseTheme.TextColor)
        .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
    }

    public class OptionEntryCell : OptionCell
    {
        public static readonly BindableProperty TextProperty = Helper.Create<string, OptionEntryCell>(nameof(Text));
        public static readonly BindableProperty KeyboardProperty = Helper.Create<Keyboard, OptionEntryCell>(nameof(Keyboard), defaultValue: Keyboard.Default);
        public static readonly BindableProperty PlaceholderProperty = Helper.Create<string, OptionEntryCell>(nameof(Placeholder));

        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }
        public Keyboard Keyboard
        {
            get => (Keyboard)GetValue(KeyboardProperty);
            set => SetValue(KeyboardProperty, value);
        }
        public string Placeholder
        {
            get => (string)GetValue(PlaceholderProperty);
            set => SetValue(PlaceholderProperty, value);
        }

        public event EventHandler<FocusEventArgs> Unfocused;

        protected override View Content
        {
            get
            {
                var content = new OptionEntry
                {
                    HorizontalOptions = LayoutOptions.Fill,
                    HorizontalTextAlignment = TextAlignment.End,
                    VerticalOptions = LayoutOptions.Fill,
                    VerticalTextAlignment = TextAlignment.Center,
                    ReturnType = ReturnType.Next
                }
                .Binding(Entry.TextProperty, nameof(Text), mode: BindingMode.TwoWay)
                .Binding(InputView.KeyboardProperty, nameof(Keyboard))
                .Binding(Entry.PlaceholderProperty, nameof(Placeholder))
                .DynamicResource(Entry.TextColorProperty, BaseTheme.TextColor)
                .DynamicResource(Entry.PlaceholderColorProperty, BaseTheme.SecondaryTextColor)
                .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
                content.Unfocused += Content_Unfocused;
                return content;
            }
        }

        private void Content_Unfocused(object sender, FocusEventArgs e)
        {
            Unfocused?.Invoke(sender, e);
        }
    }

    public class OptionEditorCell : OptionVerticalCell
    {
        public static readonly BindableProperty TextProperty = Helper.Create<string, OptionEditorCell>(nameof(Text));
        public static readonly BindableProperty FontSizeProperty = Helper.Create<double, OptionEditorCell>(nameof(FontSize), defaultValue: Device.GetNamedSize(NamedSize.Default, typeof(Editor)));
        public static readonly BindableProperty KeyboardProperty = Helper.Create<Keyboard, OptionEditorCell>(nameof(Keyboard), defaultValue: Keyboard.Default);
        public static readonly BindableProperty PlaceholderProperty = Helper.Create<string, OptionEditorCell>(nameof(Placeholder));

        public string Text
        {
            get => (string)GetValue(TextProperty);
            set => SetValue(TextProperty, value);
        }
        [TypeConverter(typeof(FontSizeConverter))]
        public double FontSize
        {
            get => (double)GetValue(FontSizeProperty);
            set => SetValue(FontSizeProperty, value);
        }
        public Keyboard Keyboard
        {
            get => (Keyboard)GetValue(KeyboardProperty);
            set => SetValue(KeyboardProperty, value);
        }
        public string Placeholder
        {
            get => (string)GetValue(PlaceholderProperty);
            set => SetValue(PlaceholderProperty, value);
        }

        OptionEditor editor;

        public void SetFocus()
        {
            if (editor != null)
            {
                editor.Focus();
            }
        }

        protected override View Content => editor = new OptionEditor
        {
            HorizontalOptions = LayoutOptions.Fill,
            VerticalOptions = LayoutOptions.Fill
        }
        .Binding(Editor.TextProperty, nameof(Text), mode: BindingMode.TwoWay)
        .Binding(Editor.FontSizeProperty, nameof(FontSize))
        .Binding(InputView.KeyboardProperty, nameof(Keyboard))
        .Binding(Editor.PlaceholderProperty, nameof(Placeholder))
        .DynamicResource(Editor.TextColorProperty, BaseTheme.TextColor)
        .DynamicResource(Editor.PlaceholderColorProperty, BaseTheme.SecondaryTextColor)
        .DynamicResource(VisualElement.BackgroundColorProperty, BaseTheme.OptionTintColor);
    }
}