using System;
using InABox.Core;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using InABox.Wpf;
using InABox.WPF;
using InABox.Wpf.DynamicGrid;
using Address = InABox.Core.Address;

namespace InABox.DynamicGrid;

public class AddressEditorControl : DynamicEnclosedEditorControl<Address, AddressEditor>
{

    private Grid Grid = null!; // Late-initialized in CreateEditor
    
    //private TextBox SearchBox = null!; // Late-initialized in CreateEditor
    //private ListBox Suggestions = null!;
    private TextBox StreetBox = null!; // Late-initialized in CreateEditor
    private TextBox CityBox = null!; // Late-initialized in CreateEditor
    private TextBox StateBox = null!; // Late-initialized in CreateEditor
    private TextBox PostcodeBox = null!; // Late-initialized in CreateEditor
    private Button MapButton = null!; // Late-initialized in CreateEditor
    
    public override int DesiredHeight()
    {
        return int.MaxValue;
    }

    public override int DesiredWidth()
    {
        return int.MaxValue;
    }

    public override void SetColor(Color color)
    {
        StreetBox.Background = new SolidColorBrush(color);
        CityBox.Background = new SolidColorBrush(color);
        StateBox.Background = new SolidColorBrush(color);
        PostcodeBox.Background = new SolidColorBrush(color);
    }

    public override void SetFocus()
    {
        StreetBox.Focus();
    }

    public override void Configure()
    {
    }

   protected override FrameworkElement CreateEditor()
    {
        Grid = new Grid
        {
            VerticalAlignment = VerticalAlignment.Stretch,
            HorizontalAlignment = HorizontalAlignment.Stretch
        };
        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });
        Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Auto) });

        //Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });
        Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
        Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Auto) });

        // SearchBox = new TextBox();
        // SearchBox.SetValue(Grid.RowProperty, 0);
        // SearchBox.SetValue(Grid.ColumnProperty, 0);
        // SearchBox.SetValue(Grid.ColumnSpanProperty, 4);
        // SearchBox.TextChanged += (sender, args) =>
        // {
        //     bool visible = SearchBox.Text.Length >= 5;
        //     if (visible != (Suggestions.Visibility == Visibility.Visible))
        //         ShowSearch(visible);
        //     if (visible)
        //     {
        //         var addresses = Client.Query<AddressLookup>(
        //             new Filter<AddressLookup>(x => x.Address).BeginsWith(SearchBox.Text),
        //             Columns.None<AddressLookup>().Add(x => x.Address));
        //             Suggestions.ItemsSource =
        //                 addresses.ExtractValues<AddressLookup, string>(x => x.Address).OrderBy(x => x).ToArray();
        //             
        //     }
        // };
        // Grid.Children.Add(SearchBox);
        //
        // Suggestions = new ListBox();
        // Suggestions.SetValue(Grid.RowProperty, 1);
        // Suggestions.SetValue(Grid.RowSpanProperty, 2);
        // Suggestions.SetValue(Grid.ColumnProperty, 0);
        // Suggestions.SetValue(Grid.ColumnSpanProperty, 4);
        // Suggestions.Visibility = Visibility.Collapsed;
        // Suggestions.SelectionChanged += (sender, args) =>
        // {
        //     SearchBox.Text = "";
        //     //ShowSearch(false);
        // };
        // Grid.Children.Add(Suggestions);
        
        StreetBox = CreateBox(0, 0, 4, 0, 0.0, 0.0, nameof(Address.Street), "Street");
        CityBox = CreateBox(1, 0, 1, 0, 0.0, 5.0, nameof(Address.City),"City");
        StateBox = CreateBox(1, 1, 1, 150, 5.0, 5.0, nameof(Address.State),"State");
        PostcodeBox = CreateBox(1,2,1,80, 5.0, 5.0, nameof(Address.PostCode),"Postcode");

        MapButton = new Button();
        MapButton.SetValue(Grid.RowProperty,1);
        MapButton.SetValue(Grid.ColumnProperty,3);
        MapButton.Width = 25.0;
        MapButton.Margin = new Thickness(5.0, 5.0, 0.0, 0.0);
        MapButton.BorderThickness = new Thickness(0.75);
        MapButton.Background = Brushes.Transparent;
        MapButton.Content = new Image() { Source = InABox.Wpf.Resources.map.AsBitmapImage() };
        MapButton.Click += (sender, args) => ShowMap();
        MapButton.Visibility = EditorDefinition.ShowMapButton 
            ? Visibility.Visible 
            : Visibility.Collapsed;
        Grid.Children.Add(MapButton);
        
        return Grid;
    }

    // private void ShowSearch(bool suggestions)
    // {
    //     Suggestions.Visibility = suggestions ? Visibility.Visible : Visibility.Collapsed;
    //     StreetBox.Visibility = suggestions ? Visibility.Collapsed : Visibility.Visible;
    //     CityBox.Visibility = suggestions ? Visibility.Collapsed : Visibility.Visible;
    //     StateBox.Visibility = suggestions ? Visibility.Collapsed : Visibility.Visible;
    //     PostcodeBox.Visibility = suggestions ? Visibility.Collapsed : Visibility.Visible;
    //     MapButton.Visibility = suggestions ? Visibility.Collapsed : Visibility.Visible;
    // }

    private void ShowMap()
    {
        var values = new Dictionary<string,object?>(GetChildValues());

        var address = new Address();
        if (values.TryGetValue(nameof(Address.Street), out var street)) 
            address.Street = street?.ToString() ?? "";
        if (values.TryGetValue(nameof(Address.City), out var city)) 
            address.City = city?.ToString() ?? "";
        if (values.TryGetValue(nameof(Address.State), out var state)) 
            address.State = state?.ToString() ?? "";
        if (values.TryGetValue(nameof(Address.PostCode), out var postcode)) 
            address.PostCode = postcode?.ToString() ?? "";
        if (values.TryGetValue(nameof(Address.Geofence), out var geofence)) 
            address.Geofence = geofence?.ToString() ?? "";
        if (values.TryGetValue($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}", out var latitude)) 
            address.Location.Latitude = latitude != null ? (double)latitude : 0.0;
        if (values.TryGetValue($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}", out var longitude)) 
            address.Location.Longitude = longitude != null ? (double)longitude : 0.0;
        
        var map = new GeofenceEditor(address, true);
        map.ShowDialog();
        _latitude = address.Location.Latitude;
        _longitude = address.Location.Longitude;
        _geofence = address.Geofence;
        
        CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}");
        CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}");
        CheckChanged(nameof(Address.Geofence));

    }

    private TextBox CreateBox(int row, int col, int colspan, double minWidth, double leftpad, double toppad, string property, string watermark)
    {
        var box = new TextBox();
        box.SetValue(Grid.RowProperty,row);
        box.SetValue(Grid.ColumnProperty,col);
        box.SetValue(Grid.ColumnSpanProperty,Math.Max(1,colspan));
        box.MinWidth = minWidth;
        box.Margin = new Thickness(leftpad, toppad, 0, 0);
        box.TextChanged += AddressChanged;
        box.LostFocus += CheckChanged;
        box.Tag = property;
        TextBoxUtils.SetPlaceholder(box, watermark);
        Grid.Children.Add(box);
        return box;
    }

    private bool _dirty = false;
    
    private void CheckChanged(object sender, RoutedEventArgs e)
    {
        if (sender is not TextBox box)
            return;
        
        CheckChanged((box.Tag as string)!);

        if (_dirty)
        {
            _latitude = 0.0;
            _longitude = 0.0;
            _geofence = "";
            CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}");
            CheckChanged($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}");
            CheckChanged($"{nameof(Address.Geofence)}");
            _dirty = false;
        }
        MapButton.Background = string.IsNullOrWhiteSpace(_geofence) ? Brushes.Red : Brushes.LightGreen;
        
    }

    private void AddressChanged(object sender, TextChangedEventArgs e)
    {
        _dirty = true;
    }

    public override void SetEnabled(bool enabled)
    {
        StreetBox.IsEnabled = enabled;
        CityBox.IsEnabled = enabled;
        StateBox.IsEnabled = enabled;
        PostcodeBox.IsEnabled = enabled;
        base.SetEnabled(enabled);
    }
    
    protected override object? GetChildValue(string property)
    {
        if (string.Equals(property,nameof(Address.Street))) 
            return StreetBox.Text;
        if (string.Equals(property,nameof(Address.City))) 
            return CityBox.Text;
        if (string.Equals(property,nameof(Address.State))) 
            return StateBox.Text;
        if (string.Equals(property,nameof(Address.PostCode))) 
            return PostcodeBox.Text;
        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}"))
            return _latitude;
        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}"))
            return _longitude;
        if (string.Equals(property,nameof(Address.Geofence))) 
            return _geofence;
        return null;
    }

    protected override IEnumerable<KeyValuePair<string, object?>> GetChildValues()
    {
        yield return new(nameof(Address.Street), StreetBox.Text);
        yield return new(nameof(Address.City), CityBox.Text);
        yield return new(nameof(Address.State), StateBox.Text);
        yield return new(nameof(Address.PostCode), PostcodeBox.Text);
        yield return new($"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}", _latitude);
        yield return new($"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}", _longitude);
        yield return new(nameof(Address.Geofence), _geofence);
    }

    private double _latitude = 0.0;
    private double _longitude = 0.0;
    private String _geofence = "";

    protected override void SetChildValue(string property, object? value)
    {
        if (string.Equals(property,nameof(Address.Street))) 
            StreetBox.Text = value?.ToString() ?? "";
        if (string.Equals(property,nameof(Address.City))) 
            CityBox.Text = value?.ToString() ?? "";
        if (string.Equals(property,nameof(Address.State))) 
            StateBox.Text = value?.ToString() ?? "";
        if (string.Equals(property,nameof(Address.PostCode))) 
            PostcodeBox.Text = value?.ToString() ?? "";
        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Latitude)}"))
            _latitude = (double?)value ?? 0.0;
        if (string.Equals(property, $"{nameof(Address.Location)}.{nameof(Address.Location.Longitude)}"))
            _longitude = (double?)value ?? 0.0;
        if (string.Equals(property, nameof(Address.Geofence)))
        {
            _geofence = value?.ToString() ?? "";
            MapButton.Background = string.IsNullOrWhiteSpace(_geofence) ? Brushes.Red : Brushes.LightGreen;
        }

    }

}