using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using pavesys_iRAP.Helper;
using pavesys_iRAP.ViewModels;
using System.Linq;
using Mapsui.Projections;
using Mapsui.Nts.Extensions;
using Mapsui.Extensions;
using Mapsui;
using NetTopologySuite.Geometries;
using System.Collections.Generic;
using pavesys_iRAP.Business;
using SharpKml.Dom;
using SharpKml.Engine;
using System.Diagnostics;
using System.IO;
using Avalonia.Interactivity;
using Avalonia.Platform.Storage;
using DocumentFormat.OpenXml.Spreadsheet;
using NetTopologySuite.LinearReferencing;
using System;

namespace pavesys_iRAP.Views;

public partial class InputCorrectionPageView : UserControl
{
    public InputCorrectionPageView()
    {
        InitializeComponent();


    }

    private void InitializeMaps(MPoint point)
    {
        this.InterpolatedMap.Map = new();
        this.DefaultMap.Map = new();
        this.KmlMap.Map = new();

        DefaultMap.Map.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer("pavesys-iRAP"));
        InterpolatedMap.Map.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer("pavesys-iRAP"));
        KmlMap.Map.Layers.Add(Mapsui.Tiling.OpenStreetMap.CreateTileLayer("pavesys-iRAP"));

        DefaultMap.Map.Home = n => n.CenterOnAndZoomTo(point, 10);
        DefaultMap.Map.Refresh();
        DefaultMap.Refresh();

        InterpolatedMap.Map.Home = n => n.CenterOnAndZoomTo(point, 10);

        InterpolatedMap.Map.Refresh();
        InterpolatedMap.Refresh();

        KmlMap.Map.Home = n => n.CenterOnAndZoomTo(point, 10);

        KmlMap.Map.Refresh();
        KmlMap.Refresh();

    }



    private void UserControl_DataContextChanged(object? sender, System.EventArgs e)
    {
        var dtx = this.DataContext as InputCorrectionPageViewModel;
        double summDiff = 0;
        for (int i = 0; i < dtx.xmlLogs.Count -1; i++) {
            summDiff += InputXML.GetVincentyDistance((double)dtx.xmlLogs[i].LonLatGPGGA.Item2, (double)dtx.xmlLogs[i].LonLatGPGGA.Item1,
                (double)dtx.xmlLogs[i + 1].LonLatGPGGA.Item2, (double)dtx.xmlLogs[i + 1].LonLatGPGGA.Item1);
        }
        //Debug.WriteLine(summDiff);



        var middleLog = dtx.xmlLogs[dtx.xmlLogs.Count / 2];
        var middlePoint = SphericalMercator.FromLonLat((double)middleLog.LonLatGPGGA.Item1, (double)middleLog.LonLatGPGGA.Item2).ToMPoint();
        InitializeMaps(middlePoint);
        //Adiciona a LineString do xml.
        DefaultMap.Map.Layers.Add(MapHelper.CreateLineStringLayer(dtx.xmlLogs.Select(log =>
            SphericalMercator.FromLonLat((double)log.LonLatGPGGA.Item1, (double)log.LonLatGPGGA.Item2)
            .ToCoordinate())
                .ToArray(),
                MapHelper.CreateLineStringStyle())
            );
        InterpolatedMap.Map.Layers.Add(MapHelper.CreateLineStringLayer(dtx.xmlInterpolatedLogs.Select(log =>
           SphericalMercator.FromLonLat((double)log.LonLatGPGGA.Item1, (double)log.LonLatGPGGA.Item2)
           .ToCoordinate())
               .ToArray(),
               MapHelper.CreateLineStringStyle())
           );
        //Pinta de vermelho os segmentos com repetição de coordenada na linestring.
        if (dtx.errorDic is not null)
        {
            var errorsDic = dtx.errorDic.Where(list => list.Value.Count >= 3 && list.Value.Count <= ConfigManager.GetInputErrorLimit());
            var errorsDicNotUsed = dtx.errorDic.Where(list => list.Value.Count >= ConfigManager.GetInputErrorLimit());
            foreach (var errorDic in errorsDic)
            {
              
                //Desenha as linhas vermelhas dos erros no e as verdes das interpolações
                if (errorDic.Value.Last() < dtx.xmlLogs.Count - 2) // necessário para checar se não vamos tentar acessar uma posição de fora do array, no máximo vamos deixar de interpolar a última coordenada com erro.
                {
                    //Debug.WriteLine(errorDic.Value.Last());
                    List<Coordinate> coordinates = new();
                    var firstLog = dtx.xmlLogs[errorDic.Value.First() - 1];
                    var firstPoint = SphericalMercator.FromLonLat((double)firstLog.LonLatGPGGA.Item1, (double)firstLog.LonLatGPGGA.Item2).ToCoordinate();
                    var lastLog = dtx.xmlLogs[errorDic.Value.Last() + 2];
                    var lastPoint = SphericalMercator.FromLonLat((double)lastLog.LonLatGPGGA.Item1, (double)lastLog.LonLatGPGGA.Item2).ToCoordinate();
                    coordinates.Add(firstPoint);
                    coordinates.Add(lastPoint);
                    DefaultMap.Map.Layers.Add(MapHelper.CreateLineStringLayer(coordinates.ToArray(), MapHelper.CreateLineStringWillInterpolateStyle()));

                    //Interpolação dos pontos
                    int totalPoints = errorDic.Value.Count + 1;
                    var start = dtx.xmlLogs[errorDic.Value.First() - 1].LonLatGPGGA;
                    var end = dtx.xmlLogs[errorDic.Value.Last() + 2].LonLatGPGGA;
                    Coordinate[] newCoordinates = new Coordinate[totalPoints];
                    newCoordinates[0] = SphericalMercator.FromLonLat((double)start.Item1, (double)start.Item2).ToCoordinate();
                    newCoordinates[totalPoints - 1] = SphericalMercator.FromLonLat((double)end.Item1, (double)end.Item2).ToCoordinate();
                    for (int i = 1; i < totalPoints - 1; i++)
                    {
                        double t = (double)i / (totalPoints - 1);
                        double x = (double)start.Item1 + t * (double)(end.Item1 - start.Item1);
                        double y = (double)start.Item2 + t * (double)(end.Item2 - start.Item2);
                        newCoordinates[i] = SphericalMercator.FromLonLat(x, y).ToCoordinate();
                    }
                    InterpolatedMap.Map.Layers.Add(MapHelper.CreateLineStringLayer(newCoordinates, MapHelper.CreateLineStringInterpolatedStyle()));

                }
            }
            if (errorsDicNotUsed.Count() > 0) {
                DialogHelper.ShowOkDialog("Warning","OverLimitInterpolation");
            foreach (var errorDic in errorsDicNotUsed)
            {
                if (errorDic.Value.Last() < dtx.xmlLogs.Count - 2) // necessário para checar se não vamos tentar acessar uma posição de fora do array, no máximo vamos deixar de interpolar a última coordenada com erro.
                {
                    Debug.WriteLine(errorDic.Value.Last());
                    List<Coordinate> coordinates = new();
                    var firstLog = dtx.xmlLogs[errorDic.Value.First() - 1];
                    var firstPoint = SphericalMercator.FromLonLat((double)firstLog.LonLatGPGGA.Item1, (double)firstLog.LonLatGPGGA.Item2).ToCoordinate();
                    var lastLog = dtx.xmlLogs[errorDic.Value.Last() + 2];
                    var lastPoint = SphericalMercator.FromLonLat((double)lastLog.LonLatGPGGA.Item1, (double)lastLog.LonLatGPGGA.Item2).ToCoordinate();
                    coordinates.Add(firstPoint);
                    coordinates.Add(lastPoint);
                    InterpolatedMap.Map.Layers.Add(MapHelper.CreateLineStringLayer(coordinates.ToArray(), MapHelper.CreateLineStringErrorStyle()));
                }
            }
            }

        }

        

    }



    private async void FolderButtonClick(object sender, RoutedEventArgs e)
    {
        var topLevel = TopLevel.GetTopLevel(this);

        var files = await topLevel.StorageProvider.OpenFilePickerAsync(new FilePickerOpenOptions
        {
            Title = "Pick kml file",
            AllowMultiple = false
        });

        if (files.Count > 0)
        {
            if (files.ElementAt(0).Name.EndsWith(".kml"))
            {
                var path = files.ElementAt(0).TryGetLocalPath();
                // Desenha mapa do kml
                NetTopologySuite.Geometries.LineString LineStringKml;
                using (var stream = File.Open(path, FileMode.Open))
                {
                    KmlFile kmlFile = KmlFile.Load(stream);
                    //var placemarks = kmlFile.Root.Flatten().OfType<Placemark>();
                    var root = kmlFile.Root as Kml;
                    var placemarks = root.Flatten().OfType<SharpKml.Dom.LineString>();

                    //Find the LineString elements
                    //var lineStrings = placemarks.Select(pm => pm.Geometry)
                    //                           .OfType<SharpKml.Dom.LineString>();
                    var dtx = this.DataContext as InputCorrectionPageViewModel;
                    var lineStrings = placemarks;
                    var linestringTeste = lineStrings.ElementAt(0);
                    for(int i =0; i < linestringTeste.Coordinates.Count; i++) 
                    {
                        var coord = linestringTeste.Coordinates.ElementAt(i);
                        if (double.IsNaN(coord.Latitude)|| double.IsNaN(coord.Longitude) || coord.Latitude == null || coord.Longitude == null) {
                            Debug.WriteLine($"Indice={i}");
                        }
                    }
                    //NetTopologySuite.Geometries.LineString linestringTeste = 
                    LineStringKml = new(lineStrings.ElementAt(0).Coordinates.Select(coord => SphericalMercator.FromLonLat(coord.Longitude, coord.Latitude).ToCoordinate()).ToArray());
                    for (int i = 0; i < LineStringKml.Coordinates.Count(); i++)
                    {
                        var coord = linestringTeste.Coordinates.ElementAt(i);
                        if (double.IsNaN(coord.Latitude) || double.IsNaN(coord.Longitude) || coord.Latitude == null || coord.Longitude == null)
                        {
                            Debug.WriteLine($"Indice={i}");
                        }
                    }

                    dtx.LineStringKml = LineStringKml;

                    KmlMap.Map.Layers.Add(MapHelper.CreateLineStringLayer(LineStringKml, MapHelper.CreateLineStringStyle()));
                }
            }
            else
            {

            }

        }


    }
}