using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using MsBox.Avalonia.Dto;
using MsBox.Avalonia.Models;
using MsBox.Avalonia;
using pavesys_iRAP.Business;
using pavesys_iRAP.DTO;
using pavesys_iRAP.Helper;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using Serilog;
using System.Threading.Tasks;
using Avalonia.Notification;

using NetTopologySuite.Geometries;
using Newtonsoft.Json;
using System.Text;
using Mapsui.Projections;

namespace pavesys_iRAP.ViewModels
{
    public partial class NewProjectPageViewModel : ViewModelBase
    {

        [ObservableProperty]
        private INotificationMessageManager manager = new NotificationMessageManager();
        //Qual campo foi mexido, o de inicio ou fim do trecho.
        public enum LoadXmlOption
        {
            StartKM,
            EndKM
        }
        public bool isNotLoading { get; set; } = true;
        //Usado para tratar o xml.
        public InputXML xmlLog;
        [ObservableProperty]
        private string projRoad;
        [ObservableProperty]
        private string projDescription;
        [ObservableProperty]
        private string projEncoder;
        [ObservableProperty]
        private string projPath;
        [ObservableProperty]
        private string projTrecho;
        [ObservableProperty]
        private bool isMph = false;
        [ObservableProperty]
        private string csvFilePath;

        public Dictionary<(decimal, decimal), List<int>> errorDictionary;
        public bool hasCoordinateError = false;
        private bool isUpdating = false;
        public decimal? projInitialKM = 0;
        public decimal? ProjInitialKM
        {
            get => projInitialKM;
            set
            {
                SetProperty(ref projInitialKM, value);
                if (!isUpdating)
                {

                    if (!string.IsNullOrEmpty(projXmlPath))
                    {
                        isUpdating = true;
                        LoadXmlProj(LoadXmlOption.StartKM);
                        isUpdating = false;
                    }
                }
            }
        }

        public decimal? projEndKM = 0;
        public decimal? ProjEndKM
        {
            get => projEndKM;
            set
            {
                SetProperty(ref projEndKM, value);
                if (!isUpdating)
                {

                    if (!string.IsNullOrEmpty(projXmlPath))
                    {
                        isUpdating = true;
                        LoadXmlProj(LoadXmlOption.EndKM);
                        isUpdating = false;
                    }
                }
            }
        }

        [ObservableProperty]
        private decimal projDisplacement;
        [ObservableProperty]
        private decimal projPulse;
        [ObservableProperty]
        private bool isPhotosNotSelected;

        private bool isPulseNegative;
        public bool IsPulseNegative
        {
            get => isPulseNegative;
            set
            {
                SetProperty(ref isPulseNegative, value);
                if (projXmlPath != "" && projXmlPath != null)
                {
                    LoadXmlProj(LoadXmlOption.StartKM);
                }
            }
        }


        public string firstImage;
        public string lastImage;

        private string projXmlPath;
        public string ProjXmlPath
        {
            get => projXmlPath;
            set
            {
                SetProperty(ref projXmlPath, value);
                if (projXmlPath != "" && projXmlPath != null)
                {
                    isDistanceCalculated = false;
                    LoadXmlProj(LoadXmlOption.StartKM);
                    hasCoordinateError = xmlLog.OutputRepeatedCoordinatesError(xmlLog.logs, out errorDictionary);
                }
            }
        }
        public bool isDistanceCalculated = false;
        private decimal CalculatedDistance;
        private decimal CalculatedPulse;
        private decimal CalculatedDisplacement;

        [ObservableProperty]
        private bool preCodeCurvature;
        //Setted in the code behind after folder is chosen
        [ObservableProperty]
        private ObservableCollection<string> xmlFiles;

        public RelayCommand loadXmlProj { get; }
        public RelayCommand saveXmlProj { get; }
        public RelayCommand reloadPage { get; }
        public NewProjectPageViewModel()
        {
            //loadXmlProj = new RelayCommand(LoadXmlProj);
            //saveXmlProj = new RelayCommand(SaveXmlProject);
            reloadPage = new RelayCommand(ReloadPage);
        }

        private void ReloadPage()
        {
            ProjRoad = "";
            ProjDescription = "";
            ProjEncoder = "";
            ProjPath = "";
            ProjTrecho = "";
            ProjInitialKM = 0;
            ProjEndKM = 0;
            ProjDisplacement = 0;
            ProjPulse = 0;
            ProjXmlPath = "";
        }


        public void LoadXmlProj(LoadXmlOption StartOrEnd)
        {

            if (!isDistanceCalculated)
            {
                xmlLog = new InputXML(projXmlPath);
                //A criação do input xml cria uma mensagem de erro de leitura xml caso aconteça então aqui só precisamos não continuar a função
                //caso tenha tido erro na leitura.
                if (xmlLog.logs.FirstOrDefault() != null)
                {
                    if (IsPhotosNotSelected)
                        xmlLog.calculatePulse(xmlLog.logs, 0, 0, out CalculatedDisplacement, out CalculatedPulse, out CalculatedDistance);
                    else
                    {
                        xmlLog.calculatePulse(xmlLog.logs, int.Parse(firstImage.Split('.')[0]), int.Parse(lastImage.Split('.')[0]), out CalculatedDisplacement, out CalculatedPulse, out CalculatedDistance);
                    }
                    isDistanceCalculated = true;
                }
                //Aqui retornamos caso tenha tido erro na leitura
                else { return; }
            }
            switch (StartOrEnd)
            {
                case LoadXmlOption.StartKM:
                    if (ProjInitialKM == null)
                        return;
                    if (!IsPulseNegative)
                        ProjEndKM = Math.Truncate((decimal)(CalculatedDistance + ProjInitialKM) * 10) / 10;
                    //ProjEndKM = CalculatedDistance + ProjInitialKM;
                    else
                        ProjEndKM = Math.Truncate((decimal)(ProjInitialKM - CalculatedDistance) * 10) / 10;
                    //ProjEndKM = (ProjInitialKM - CalculatedDistance);
                    break;
                case LoadXmlOption.EndKM:
                    if (ProjEndKM == null)
                        return;
                    if (!IsPulseNegative)
                        ProjInitialKM = Math.Truncate((decimal)(ProjEndKM - CalculatedDistance) * 10) / 10;
                    //ProjInitialKM = (ProjEndKM - CalculatedDistance);

                    else
                        ProjInitialKM = Math.Truncate((decimal)(ProjEndKM + CalculatedDistance) * 10) / 10;
                    //ProjInitialKM = (ProjEndKM + CalculatedDistance);

                    break;
            }

            //Para passar o displacement para km
            ProjDisplacement = CalculatedDisplacement / 1000;
            ProjPulse = CalculatedPulse;

            //Garante que não haja km negativos
            //if (ProjInitialKM < 0)
            //    ProjInitialKM = 0;
            //if (ProjEndKM < 0)
            //    ProjEndKM = 0;

            if (IsPulseNegative)
                ProjPulse = -ProjPulse;
        }
        public async Task<bool> SaveProject(List<LogXML> logsXml)
        {
            //xmlLog = new InputXML(projXmlPath);
            Log.Debug("Saving Project");
            string output = JsonConvert.SerializeObject(logsXml[0], Formatting.None);
            Log.Debug(output);
            xmlLog.logs = logsXml;
            var CreateProject = new Project();
            CreateProject.ProjectPath = ProjPath;
            CreateProject.ProjectDescription = ProjDescription;
            CreateProject.Road = ProjRoad;
            CreateProject.CoderName = ProjEncoder;
            CreateProject.Section = ProjTrecho;
            CreateProject.Status = 0;
            CreateProject.KmStart = (decimal)ProjInitialKM;
            CreateProject.KmEnd = (decimal)ProjEndKM;
            CreateProject.SurveySheetName = Path.GetFileName(ProjXmlPath);
            CreateProject.IsMph = IsMph;
            //ViaSeguraLabeled não aceita null no banco de dados
            if (PreCodeCurvature)
                CreateProject.ViaSeguraLabeled = "PreCurvature,";
            else
                CreateProject.ViaSeguraLabeled = string.Empty;
            //ExternalUrl não aceita null no banco de dados
            CreateProject.ExternalUrl = " ";


            List<(int, int)> missingPhotos = new();
            bool hasJump = false;
            string folderPath = Path.Combine(ProjPath, "CAM 1");
            string[] files = Directory.GetFiles(folderPath, "*.jpg");

            var numbers = files
                .Select(f => Path.GetFileNameWithoutExtension(f))
                .Select(n => int.Parse(n))
                .OrderBy(n => n)
                .ToList();
            var sbCam1 = new StringBuilder();
            for (int i = 1; i < numbers.Count; i++)
            {
                int diff = numbers[i] - numbers[i - 1];
                if (diff > 5)
                {
                    missingPhotos.Append((numbers[i - 1], numbers[i]));
                    sbCam1.AppendLine($"{numbers[i - 1]:0000000000}  {numbers[i]:0000000000}");
                    hasJump = true;
                }
            }


            List<(int, int)> missingPhotosCam2 = new();

            string[] filesCam2 = Directory.GetFiles(Path.Combine(ProjPath, "CAM 2"), "*.jpg");

            var numbersCam2 = filesCam2
                .Select(f => Path.GetFileNameWithoutExtension(f))
                .Select(n => int.Parse(n))
                .OrderBy(n => n)
                .ToList();
            var sbCam2 = new StringBuilder();
            for (int i = 1; i < numbersCam2.Count; i++)
            {
                int diff = numbersCam2[i] - numbersCam2[i - 1];
                if (diff > 5)
                {
                    missingPhotosCam2.Append((numbersCam2[i - 1], numbersCam2[i]));
                    sbCam2.AppendLine($"{numbersCam2[i - 1]:0000000000}  {numbersCam2[i]:0000000000}");
                    hasJump = true;
                }
            }
            if (hasJump)
            {
                var dialog = MessageBoxManager.GetMessageBoxCustom(
                    new MessageBoxCustomParams
                    {
                        ButtonDefinitions = new List<ButtonDefinition>
                        {
                            new ButtonDefinition { Name = Localizer.Localizer.Instance["Yes"], },
                            new ButtonDefinition { Name = Localizer.Localizer.Instance["No"], }
                        },

                        ContentTitle = Localizer.Localizer.Instance["Warning"],
                        ContentMessage = $"{Localizer.Localizer.Instance["MissingPhotos"]} \n CAM 1: \n{sbCam1} \n CAM 2:\n{sbCam2}\n {Localizer.Localizer.Instance["Continue"]}",
                        Icon = MsBox.Avalonia.Enums.Icon.Info,
                        WindowStartupLocation = WindowStartupLocation.CenterOwner,
                        CanResize = false,
                        MaxWidth = 500,
                        MaxHeight = 800,

                        SizeToContent = SizeToContent.Width,
                        ShowInCenter = true,
                        Topmost = false,

                    });
                var result = await dialog.ShowAsync();
                if (result == Localizer.Localizer.Instance["No"])
                {
                    return false;
                }

            }
            try
            {
                //Caso for usada a opção de input de um csv anterior ajustar os kms iniciais e finais do projeto 
                //Seta também se é km ou milhas
                if (CsvFilePath != string.Empty && CsvFilePath != null)
                {
                    var lines = File.ReadAllLines(CsvFilePath);
                    lines = lines.Skip(1).ToArray();
                    CreateProject.KmStart = Decimal.Parse(lines[0].Split(";")[6]);
                    CreateProject.KmEnd = Decimal.Parse(lines.Last().Split(";")[6]) + 0.1M;
                    if (int.Parse(lines[0].Split(";")[22]) >= 30)
                        CreateProject.IsMph = true;
                    else
                        CreateProject.IsMph = false;
                }

                CrudHelper.dbCtx.Projects.Add(CreateProject);
                CrudHelper.dbCtx.SaveChanges();
                Log.Debug("Project Created without codings");
                if (IsPhotosNotSelected)
                {
                    Log.Debug("Creating Codings photos not selected");
                    var startTrecho = xmlLog.logs.First().Id;
                    var endTrecho = xmlLog.logs.Last().Id;
                    Log.Debug($"{startTrecho}-{endTrecho}");
                    if (CsvFilePath != string.Empty && CsvFilePath != null)
                    {
                        CrudHelper.CreateProjectPreviousOutput(this.xmlLog, CsvFilePath, CreateProject, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"));
                    }
                    else
                        CrudHelper.CreateProjectXml(this.xmlLog, CreateProject, startTrecho, endTrecho, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"), Math.Abs(ProjPulse));


                }
                else
                {
                    Log.Debug("Creating Codings photos selected");
                    var startTrecho = xmlLog.logs.Where(log => int.Parse(firstImage.Split('.')[0]) == log.Odometro).First().Id;
                    var endTrecho = xmlLog.logs.Where(log => int.Parse(lastImage.Split('.')[0]) == log.Odometro).First().Id;
                    Log.Debug($"{startTrecho}-{endTrecho}");

                    if (CsvFilePath != string.Empty && CsvFilePath != null)
                    {
                        CrudHelper.CreateProjectPreviousOutput(this.xmlLog, CsvFilePath, CreateProject, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"));
                    }
                    else
                        CrudHelper.CreateProjectXml(this.xmlLog, CreateProject, startTrecho, endTrecho, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"), Math.Abs(ProjPulse));
                }
                Log.Debug("Project created with codings");
                //Cria a pasta de fotos do projeto
                List<CodingImage> codingImages = new();
                try
                {
                    codingImages = await CrudHelper.FindCodingImagesByProjectId((int)CreateProject.ProjectId);
                }
                catch (Exception ex)
                {
                    codingImages = null;
                }
                if (codingImages is not null)
                {
                    var newProjectPath = await ExportImportHandler.OutputCamFolders(codingImages, ExportImportHandler.CamFolderOption.OptionImport, CreateProject);
                    CreateProject.ProjectPath = newProjectPath;
                    //Atualiza o path no banco de dados.
                }
                CrudHelper.dbCtx.SaveChanges();

                //Retirar codificações de trechos de 100 metros onde não existem fotos. >=100 sem foto 
                decimal counterNewKm = 0;
                foreach (var cod in CrudHelper.FindCodingsByProject((int)CreateProject.ProjectId, false))
                {
                    cod.InitialKm += counterNewKm;
                    cod.FinalKm += counterNewKm;

                    if (cod.ImagesCam.Count == 0)
                    {
                        //counterNewKm += 0.1M;
                        var codInDb = CrudHelper.dbCtx.Codings.Find(cod.CodingId);
                        if (codInDb != null)
                        {
                            Debug.WriteLine($"Removed  1 - counter = {counterNewKm}");
                            CrudHelper.dbCtx.Remove(codInDb);
                        }


                    }
                }
                CrudHelper.dbCtx.SaveChanges();
                CrudHelper.RefreshContext();
                //pré codificação de curvas
                try
                {
                    if (PreCodeCurvature)
                    {
                        var codings = CrudHelper.FindCodingsByProject((int)CreateProject.ProjectId, false);
                        var last = codings.LastOrDefault().CodingId;
                        foreach (var coding in codings)
                        {
                            var images = codingImages.Where(img => img.CodingId == coding.CodingId && img.Type == 1);
                            double minRadius = 1000000;
                            List<double> Radius = new();
                            if (images.Count() >= 5)
                            {
                                for (int i = 1; i < 4; i++)
                                {
                                    //var lonlat1 = logsXml.Where(log => log.Odometro == int.Parse(images.ElementAt(i - 1).ImageName.Replace(".jpg", String.Empty))).First().LonLatGPGGA;
                                    //var lonlat2 = logsXml.Where(log => log.Odometro == int.Parse(images.ElementAt(i).ImageName.Replace(".jpg", String.Empty))).First().LonLatGPGGA;
                                    //var lonlat3 = logsXml.Where(log => log.Odometro == int.Parse(images.ElementAt(i + 1).ImageName.Replace(".jpg", String.Empty))).First().LonLatGPGGA;
                                    //O que acontece aqui? 
                                    //Assumindo que o projeto foi bem criado, se a codificação possuir 5 fotos. vai olhar entre elas de 3 em 3 ou seja distâncias de 20 metros
                                    //Porque o +1 no indice de logsXml no final, não sei 
                                    var lonlat1 = logsXml[int.Parse(images.ElementAt(i - 1).ImageName.Replace(".jpg", String.Empty)) + 1].LonLatGPGGA;
                                    var lonlat2 = logsXml[int.Parse(images.ElementAt(i).ImageName.Replace(".jpg", String.Empty)) + 1].LonLatGPGGA;
                                    var lonlat3 = logsXml[int.Parse(images.ElementAt(i + 1).ImageName.Replace(".jpg", String.Empty)) + 1].LonLatGPGGA;
                                    minRadius = Math.Min(minRadius, RadiusCalc.Circumcircle_Radius(lonlat1, lonlat2, lonlat3));
                                }
                                coding.Curvature = RadiusCalc.RadiusToIrapIndex(minRadius);
                                Log.Debug($"{coding.CodingId}/{last} ");
                            }
                        }
                    }
                    CrudHelper.dbCtx.SaveChanges();
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Failed to pre code curvatures");
                }



                return true;
            }
            catch (Exception e)
            {
                Log.Error("Entered Catch SaveProject");
                Debug.WriteLine(e.Message);
                Log.Error(e, "Error Creating Project");
                return false;
            }
        }

        public async Task<bool> SaveProject(LineString densifiedLineString)
        {
            //xmlLog = new InputXML(projXmlPath);
            var CreateProject = new Project();
            CreateProject.ProjectPath = projPath;
            CreateProject.ProjectDescription = projDescription;
            CreateProject.Road = projRoad;
            CreateProject.CoderName = projEncoder;
            CreateProject.Section = projTrecho;
            CreateProject.Status = 0;
            CreateProject.KmStart = (decimal)projInitialKM;
            CreateProject.KmEnd = (decimal)projEndKM;
            CreateProject.SurveySheetName = Path.GetFileName(ProjXmlPath);
            CreateProject.IsMph = IsMph;
            CreateProject.ViaSeguraLabeled = "";
            //ViaSeguraLabeled não aceita null no banco de dados
            if (PreCodeCurvature)
                CreateProject.ViaSeguraLabeled = "PreCurvature,";
            else
                CreateProject.ViaSeguraLabeled = string.Empty;
            //ExternalUrl não aceita null no banco de dados
            CreateProject.ExternalUrl = "";

            List<(int, int)> missingPhotos = new();
            bool hasJump = false;
            string folderPath = Path.Combine(ProjPath, "CAM 1");
            string[] files = Directory.GetFiles(folderPath, "*.jpg");

            var numbers = files
                .Select(f => Path.GetFileNameWithoutExtension(f))
                .Select(n => int.Parse(n))
                .OrderBy(n => n)
                .ToList();
            var sbCam1 = new StringBuilder();
            for (int i = 1; i < numbers.Count; i++)
            {
                int diff = numbers[i] - numbers[i - 1];
                if (diff > 5)
                {
                    missingPhotos.Append((numbers[i - 1], numbers[i]));
                    sbCam1.AppendLine($"{numbers[i - 1]:0000000000}  {numbers[i]:0000000000}");
                    hasJump = true;
                }
            }


            List<(int, int)> missingPhotosCam2 = new();

            string[] filesCam2 = Directory.GetFiles(Path.Combine(ProjPath, "CAM 2"), "*.jpg");

            var numbersCam2 = filesCam2
                .Select(f => Path.GetFileNameWithoutExtension(f))
                .Select(n => int.Parse(n))
                .OrderBy(n => n)
                .ToList();
            var sbCam2 = new StringBuilder();
            for (int i = 1; i < numbersCam2.Count; i++)
            {
                int diff = numbersCam2[i] - numbersCam2[i - 1];
                if (diff > 5)
                {
                    missingPhotosCam2.Append((numbersCam2[i - 1], numbersCam2[i]));
                    sbCam2.AppendLine($"{numbersCam2[i - 1]:0000000000}  {numbersCam2[i]:0000000000}");
                    hasJump = true;
                }
            }
            if (hasJump)
            {
                var dialog = MessageBoxManager.GetMessageBoxCustom(
                    new MessageBoxCustomParams
                    {
                        ButtonDefinitions = new List<ButtonDefinition>
                        {
                            new ButtonDefinition { Name = Localizer.Localizer.Instance["Yes"], },
                            new ButtonDefinition { Name = Localizer.Localizer.Instance["No"], }
                        },

                        ContentTitle = Localizer.Localizer.Instance["Warning"],
                        ContentMessage = $"{Localizer.Localizer.Instance["MissingPhotos"]} \n CAM 1: \n{sbCam1} \n CAM 2:\n{sbCam2}\n {Localizer.Localizer.Instance["Continue"]}",
                        Icon = MsBox.Avalonia.Enums.Icon.Info,
                        WindowStartupLocation = WindowStartupLocation.CenterOwner,
                        CanResize = false,
                        MaxWidth = 500,
                        MaxHeight = 800,

                        SizeToContent = SizeToContent.Width,
                        ShowInCenter = true,
                        Topmost = false,

                    });
                var result = await dialog.ShowAsync();
                if (result == Localizer.Localizer.Instance["No"])
                {
                    return false;
                }

            }


            try
            {
                //Caso for usada a opção de input de um csv anterior ajustar os kms iniciais e finais do projeto 
                //Seta também se é km ou milhas
                if (CsvFilePath != string.Empty && CsvFilePath != null)
                {
                    var lines = File.ReadAllLines(CsvFilePath);
                    lines = lines.Skip(1).ToArray();
                    CreateProject.KmStart = Decimal.Parse(lines[0].Split(";")[6]);
                    CreateProject.KmEnd = Decimal.Parse(lines.Last().Split(";")[6]) + 0.1M;
                    if (int.Parse(lines[0].Split(";")[22]) >= 30)
                        CreateProject.IsMph = true;
                    else
                        CreateProject.IsMph = false;
                }

                CrudHelper.dbCtx.Projects.Add(CreateProject);
                CrudHelper.dbCtx.SaveChanges();
                if (IsPhotosNotSelected)
                {
                    Log.Debug("Creating Codings photos not selected");
                    var startTrecho = xmlLog.logs.First().Id;
                    var endTrecho = xmlLog.logs.Last().Id;
                    Log.Debug($"{startTrecho}-{endTrecho}");
                    if (CsvFilePath != string.Empty && CsvFilePath != null)
                    {
                        CrudHelper.CreateProjectPreviousOutput(this.xmlLog, CsvFilePath, CreateProject, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"));
                    }
                    else
                        CrudHelper.CreateProjectXml(this.xmlLog, CreateProject, startTrecho, endTrecho, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"), Math.Abs(ProjPulse));


                }
                else
                {
                    Log.Debug("Creating Codings photos selected");
                    var startTrecho = xmlLog.logs.Where(log => int.Parse(firstImage.Split('.')[0]) == log.Odometro).First().Id;
                    var endTrecho = xmlLog.logs.Where(log => int.Parse(lastImage.Split('.')[0]) == log.Odometro).First().Id;
                    Log.Debug($"{startTrecho}-{endTrecho}");

                    if (CsvFilePath != string.Empty && CsvFilePath != null)
                    {
                        CrudHelper.CreateProjectPreviousOutput(this.xmlLog, CsvFilePath, CreateProject, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"));
                    }
                    else
                        CrudHelper.CreateProjectXml(this.xmlLog, CreateProject, startTrecho, endTrecho, Path.Combine(ProjPath, "CAM 1"), Path.Combine(ProjPath, "CAM 2"), Math.Abs(ProjPulse));
                }


                List<CodingImage> codingImages = new();
                try
                {
                    codingImages = await CrudHelper.FindCodingImagesByProjectId((int)CreateProject.ProjectId);
                }
                catch (Exception ex)
                {
                    codingImages = null;
                }
                if (codingImages is not null)
                    CreateProject.ProjectPath = await ExportImportHandler.OutputCamFolders(codingImages, ExportImportHandler.CamFolderOption.OptionImport, CreateProject);
                CrudHelper.dbCtx.SaveChanges();

                //Retirar codificações de trechos de 100 metros onde não existem fotos. >=100 sem foto e somar 0.1 para cada segmente deletado nos próximos
                decimal counterNewKm = 0;
                foreach (var cod in CrudHelper.FindCodingsByProject((int)CreateProject.ProjectId, false))
                {
                    cod.InitialKm += counterNewKm;
                    cod.FinalKm += counterNewKm;

                    if (cod.ImagesCam.Count == 0)
                    {
                        counterNewKm += 0.1M;
                        var codInDb = CrudHelper.dbCtx.Codings.Find(cod.CodingId);
                        if (codInDb != null)
                        {
                            CrudHelper.dbCtx.Remove(codInDb);
                        }
                    }
                }

                CrudHelper.dbCtx.SaveChanges();

                //pré codificação de curvas
                try
                {
                    if (PreCodeCurvature)
                    {
                        var codings = CrudHelper.FindCodingsByProject((int)CreateProject.ProjectId, false);
                        int idxIteratorLinestring = 0;
                        foreach (var coding in codings)
                        {
                            if (idxIteratorLinestring < densifiedLineString.Count - 21)
                            {
                                double minRadius = 1000000;
                                List<double> Radius = new();
                                for (int i = 0; i < 5; i++)
                                {
                                    if (idxIteratorLinestring + 40 > densifiedLineString.Count)
                                    {
                                        break;
                                    }
                                    var lonlat1 = castDoublePairToDecimalPair(SphericalMercator.ToLonLat(densifiedLineString[idxIteratorLinestring].X, densifiedLineString[idxIteratorLinestring].Y));
                                    var lonlat2 = castDoublePairToDecimalPair(SphericalMercator.ToLonLat(densifiedLineString[idxIteratorLinestring + 20].X, densifiedLineString[idxIteratorLinestring + 20].Y));
                                    var lonlat3 = castDoublePairToDecimalPair(SphericalMercator.ToLonLat(densifiedLineString[idxIteratorLinestring + 40].X, densifiedLineString[idxIteratorLinestring + 40].Y));

                                    minRadius = Math.Min(minRadius, RadiusCalc.Circumcircle_Radius(lonlat1, lonlat2, lonlat3));
                                    idxIteratorLinestring += 20; // Distância entre pontos

                                }
                                coding.Curvature = RadiusCalc.RadiusToIrapIndex(minRadius);
                            }
                            else
                            {
                                break;
                            }
                        }
                        CrudHelper.dbCtx.SaveChanges();

                    }
                }
                catch (Exception ex)
                {
                    Log.Error(ex, "Failed to pre code curvatures");
                }

                return true;

            }
            catch (Exception e)
            {

                Debug.WriteLine(e.Message);
                Log.Error(e, "Error Creating Project");
                return false;
            }
        }

        //Só para evitar repetição na função acima.
        private (decimal, decimal) castDoublePairToDecimalPair((double, double) source)
        {
            return ((decimal)source.Item1, ((decimal)source.Item2));
        }

        public bool ValidateNewProj(out string invalidFields)
        {

            string invalidInputList = Localizer.Localizer.Instance["InvalidFieldsMsg"];
            bool valid = true;
            if (ProjPath is null || ProjPath == "")
            {
                invalidInputList += Localizer.Localizer.Instance["InvalidPath"];
                valid = false;
            }
            if (ProjDescription is null || ProjDescription == "")
            {
                invalidInputList += Localizer.Localizer.Instance["InvalidDesc"];
                valid = false;
            }
            if (ProjEncoder is null || ProjEncoder == "")
            {
                invalidInputList += Localizer.Localizer.Instance["InvalidCoder"];
                valid = false;
            }
            if (ProjRoad is null || ProjRoad == "")
            {
                invalidInputList += Localizer.Localizer.Instance["InvalidRoad"];
                valid = false;
            }
            if (ProjTrecho is null || ProjTrecho == "")
            {
                invalidInputList += Localizer.Localizer.Instance["InvalidTrecho"];
                valid = false;
            }

            if (ProjXmlPath is null || ProjXmlPath == "")
            {
                invalidInputList += Localizer.Localizer.Instance["InvalidXmlPath"];
                valid = false;
            }
            invalidFields = invalidInputList;
            return valid;
        }

    }



}
