using Mapsui.Projections;
using Mapsui.Extensions;
using Avalonia.Controls;
using Avalonia.VisualTree;
using Avalonia.Interactivity;
using BruTile.Predefined;
using Mapsui.Tiling.Layers;
using Avalonia.Controls.Primitives;
using System.Diagnostics;
using System;
using System.Linq;
using pavesys_iRAP.ViewModels;
using pavesys_iRAP.Helper;
using Mapsui.Tiling.Fetcher;
using Mapsui;
using System.Runtime.InteropServices;
using Mapsui.Nts.Extensions;

using Mapsui.Layers;
using Avalonia.Media;

namespace pavesys_iRAP.Views;
public partial class CodingPageView : UserControl
{
    MPoint Point { get; set; }
    Map SatteliteMap { get; set; }
    Map RoadMap { get; set; }
    ILayer lineLayer;
    ILayer pointLayer;


    public CodingPageView()
    {
        InitializeComponent();

        //Requisição do Mapa Sattelite
        string bingMapsApiKey = "API_TEST";
        var bingMapsLayer = new TileLayer(KnownTileSources.Create(KnownTileSource.BingHybrid, bingMapsApiKey),
            dataFetchStrategy: new DataFetchStrategy()) // DataFetchStrategy prefetches tiles from higher levels
        {
            Name = "Bing Aerial",
        };

        SatteliteMap = new Map();
        RoadMap = new Map();

        SatteliteMap.Layers.Add(bingMapsLayer);
        RoadMap.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer("pavesys-iRAP"));



        SatteliteMap.Home = n => n.ZoomToLevel(15);
        RoadMap.Home = n => n.ZoomToLevel(15);
        RoadMap.Refresh();
        SatteliteMap.Refresh();
        MapView.Refresh();
        //Inicia o mapview no 2d openstreetmap
        MapView.Map = RoadMap;


    }

    private void updateDataContext(object sender, EventArgs e)
    {
        var tab = sender as TabControl;
        tab.DataContext = this.DataContext;
        this.GetVisualDescendants().OfType<ListBox>().ToList().ForEach(list =>
        {
            list.DataContext = this.DataContext;
        });
            
        this.GetVisualDescendants().OfType<NumericUpDown>().ToList().ForEach(list =>
        {
            list.DataContext = this.DataContext;
        });

        this.GetVisualDescendants().OfType<ToggleSwitch>().ToList().ForEach(toggle =>
        {
            toggle.DataContext = this.DataContext;
            if (toggle.IsChecked == null)
            {
                toggle.Background = Brush.Parse("SlateGray");
            }
        });

        this.GetVisualDescendants().OfType<ComboBox>().ToList().ForEach(combo =>
        {
            combo.DataContext = this.DataContext;
        });

        this.GetVisualDescendants().OfType<Button>().ToList().ForEach(button =>
        {
            button.DataContext = this.DataContext;
        });

        this.GetVisualDescendants().OfType<DataGrid>().ToList().ForEach(dataGrid =>
        {
            dataGrid.DataContext = this.DataContext;
        });

        this.GetVisualDescendants().OfType<Image>().ToList().ForEach(img =>
        {
            img.DataContext = this.DataContext;
        });
    }
    private void OpenUrl(string url)
    {
        try
        {
            Process.Start(url);
        }
        catch
        {
            // hack because of this: https://github.com/dotnet/corefx/issues/10361
            if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
            {
                url = url.Replace("&", "^&");
                Process.Start(new ProcessStartInfo(url) { UseShellExecute = true });
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
            {
                Process.Start("xdg-open", url);
            }
            else if (RuntimeInformation.IsOSPlatform(OSPlatform.OSX))
            {
                Process.Start("open", url);
            }
            else
            {
                throw;
            }
        }
    }
    public void ClickManual(object sender, RoutedEventArgs args)
    {
        OpenUrl(@"https://irap.org/specifications/");
    }

    private void Cebug(object sender, RoutedEventArgs args)
    {
        Debug.WriteLine("Clicou");

    }
    private void SelectMapStyle(object sender, SelectionChangedEventArgs args)
    {
        var lb = sender as ListBox;
        switch (lb.SelectedIndex)
        {
            case 0:
                MapView.Map = RoadMap;
                MapView.Map.Navigator.CenterOn(Point);
                MapView.Refresh();
                break;

            case 1:
                MapView.Map = SatteliteMap;
                MapView.Map.Navigator.CenterOn(Point);
                MapView.Refresh();
                break;
        }
    }


    private void ApplyCheck(object sender, RoutedEventArgs args)
    {
        var toggleButton = sender as ToggleButton;

        if (toggleButton.Content != "X" && (toggleButton.IsChecked != null))
        {
            toggleButton.Content = "X";
        }
        else
        {
            toggleButton.Content = "";
        }
    }

    private void LatLonChanged(object? sender, Avalonia.Controls.NumericUpDownValueChangedEventArgs e)
    {
        var ctx = this.DataContext as CodingPageViewModel;

        //var Point = SphericalMercator.FromLonLat((double)NumLatitude.Value, (double)NumLongitude.Value).ToMPoint();
        Point = SphericalMercator.FromLonLat((double)NumLongitude.Value, (double)NumLatitude.Value).ToMPoint();

        if (lineLayer is null)
        {
            lineLayer = MapHelper.CreateLineStringLayer(ctx.codingCtx.Select(coding =>
            SphericalMercator.FromLonLat((double)coding.Longitude, (double)coding.Latitude)
            .ToCoordinate())
                .ToArray(),
                MapHelper.CreateLineStringStyle());
            RoadMap.Layers.Add(lineLayer);
            SatteliteMap.Layers.Add(lineLayer);
        }
        if (pointLayer is null)
        {
            pointLayer = MapHelper.CreatePointLayer(Point);
            RoadMap.Layers.Add(pointLayer);
            SatteliteMap.Layers.Add(pointLayer);
        }
        else
        {
            RoadMap.Layers.Remove(pointLayer);
            SatteliteMap.Layers.Remove(pointLayer);
            pointLayer = MapHelper.CreatePointLayer(Point);
            RoadMap.Layers.Add(pointLayer);
            SatteliteMap.Layers.Add(pointLayer);
        }
        RoadMap.Navigator.CenterOn(Point);
        SatteliteMap.Navigator.CenterOn(Point);
        MapView.Refresh();

    }

    private void SetTextDataContext(object? sender, System.EventArgs e)
    {
        var text = sender as TextBlock;
        text.DataContext = this.DataContext;
    }
    private void SetPBarDataContext(object? sender, System.EventArgs e)
    {
        var PB = sender as ProgressBar;
        PB.DataContext = this.DataContext;
    }

    private void DataGrid_DoubleTapped(object? sender, Avalonia.Input.TappedEventArgs e)
    {
        var vm = this.DataContext as CodingPageViewModel;


        if (e.Source is Avalonia.Controls.Border)
            vm.LoadSegfromGrid();
    }






    private void Border_SizeChanged_2(object? sender, Avalonia.Controls.SizeChangedEventArgs e)
    {
        var x = sender as Avalonia.Controls.Border;
        var y = x.GetVisualAncestors();
        var dockitem = y.ElementAt(4) as NP.Ava.UniDock.DockItemPresenter;
        dockitem.MinWidth = 392;
    }
    //Workaround to set codingview elements minimum and max width
    //It assumes it's called from the panel that contains the mapview
    //if anything in the visual structure is changed this must be done a different way.
    //Might lead to crashs with docking
    private void SetLayoutWidths(object? sender, Avalonia.Controls.SizeChangedEventArgs e)
    {
        try
        {
            var f = GridParent.GetVisualDescendants().ElementAt(6) as Avalonia.Controls.Grid;
            var topLevel = TopLevel.GetTopLevel(this) as Window;
            f.ColumnDefinitions.ElementAt(0).MaxWidth = topLevel.Width - 436;
            f.ColumnDefinitions.ElementAt(2).MinWidth = 435;
            f.ColumnDefinitions.ElementAt(2).MaxWidth = 445;
        }
        catch (System.Exception ex)
        {
            Debug.WriteLine("Erro ao definir os limites de largura:" + ex.Message);
        }

    }

    private void ToggleSwitch_IsCheckedChanged(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
    {
        var toggle = sender as ToggleSwitch;
        toggle.Background = Brush.Parse("White");
    }



   

    private void SegGridFocusOnSelectedItem(object? sender, Avalonia.Interactivity.RoutedEventArgs e)
    {
        try {
            var segGrid = sender as DataGrid;
            if (segGrid.SelectedItem != null) 
            {
                segGrid.ScrollIntoView(segGrid.SelectedItem, segGrid.Columns[2]);
            }
        }
        catch (Exception ex) {
            Debug.WriteLine(ex.Message);
        }
    }

    private void DockPanel_DoubleTapped_1(object? sender, Avalonia.Input.TappedEventArgs e)
    {
        var dtx = this.DataContext as CodingPageViewModel;
        var window = TopLevel.GetTopLevel(this);
        window.Clipboard.SetTextAsync($"{NumLatitude.Value},{NumLongitude.Value}");
    }
}