using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using pavesys_iRAP.DTO;
using pavesys_iRAP.Helper;
using Serilog;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace pavesys_iRAP.ViewModels
{
    public partial class ViaSeguraPageViewModel : ViewModelBase
    {
        public ViaSeguraPageViewModel() {
            RelayRun = new RelayCommand(Run);
        }

        [ObservableProperty]
        private int batchSize  = 4;

        [ObservableProperty]
        private bool isUpdating = false;
        [ObservableProperty]
        private bool isNotUpdating = true;
        public RelayCommand RelayRun { get; set; }
        private bool[] codingsHasAllPhotos;
        public int projectId { get; set; }

        [ObservableProperty]
        private bool delineation;

        [ObservableProperty]
        private bool streetLighting;

        [ObservableProperty]
        private bool roadCondition;

        [ObservableProperty]
        private bool skidResistance;

        [ObservableProperty]
        private bool upgradeCost;

        [ObservableProperty]
        private bool speedManagement;

        [ObservableProperty]
        private bool bicylceFacility;

        [ObservableProperty]
        private bool qualityOfCurve;

        [ObservableProperty]
        private bool vehicleParking;

        [ObservableProperty]
        private bool propertyAccessPoints;

        [ObservableProperty]
        private bool areaType;

        [ObservableProperty]
        private bool landUse;

        [ObservableProperty]
        private bool numberOfLanes;

        [ObservableProperty]
        private bool carriageway;

        [ObservableProperty]
        private bool serviceRoad;

        [ObservableProperty]
        private int currentProgress;
        [ObservableProperty]
        private int maximumProgress;
        [ObservableProperty]
        private int selectedCam;

        public string GetSelectedOptions()
        {
            List<string> selectedOptions = new List<string>();

            if (Delineation) selectedOptions.Add("delineation");
            if (StreetLighting) selectedOptions.Add("street_lighting");
            if (Carriageway) selectedOptions.Add("carriageway");
            if (ServiceRoad) selectedOptions.Add("service_road");
            if (RoadCondition) selectedOptions.Add("road_condition");
            if (SkidResistance) selectedOptions.Add("skid_resistance");
            if (UpgradeCost) selectedOptions.Add("upgrade_cost");
            if (SpeedManagement) selectedOptions.Add("speed_management");
            if (BicylceFacility) selectedOptions.Add("bicycle_facility");
            if (QualityOfCurve) selectedOptions.Add("quality_of_curve");
            if (VehicleParking) selectedOptions.Add("vehicle_parking");
            if (PropertyAccessPoints) selectedOptions.Add("property_access_points");
            if (AreaType) selectedOptions.Add("area_type");
            if (LandUse) selectedOptions.Add("land_use");
            if (NumberOfLanes) selectedOptions.Add("number_of_lanes");

            // Return the joined string separated by commas
            return string.Join(",", selectedOptions);
        }

        
        

        private async Task<string >ProcessPhotosToCSV() 
        {
            var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
                    "Pavesys", "TempViaSegura.csv");
            var codings = CrudHelper.FindCodingsByProject(projectId, false);
            bool[] codingHasAllPhotos = new bool[codings.Count];
            StringBuilder sbToCsv = new StringBuilder();
            for (int i = 0; i < codings.Count - 1; i++)
            {
                string[] codingNames = new string[5];
                StringBuilder sb = new StringBuilder();
                var codingImages = CrudHelper.dbCtx.CodingImages.Where(codimage => codimage.CodingId == codings[i].CodingId);
                if (codingImages.Count() == 10)
                {
                    codingHasAllPhotos[i] = true;
                    for (int j = 0; j < 5; j++)
                    {
                        codingNames[j] = codingImages.ElementAt(j).ImageName;
                    }
                    sb.AppendJoin(',', codingNames);
                    sbToCsv.AppendLine(sb.ToString());
                }
                else
                    codingHasAllPhotos[i] = false;
            }
            codingsHasAllPhotos = codingHasAllPhotos;
            await File.WriteAllTextAsync(filePath, sbToCsv.ToString());

            return filePath;
        }

        private async Task StartViaSeguraProcessing(string csvPath)
        {

            

            //var scriptPath = Path.Combine(@"D:\OTI Software\Desktop\OTI\Repo iRAP", "ViaSeguraModule", "test.py");

            var scriptPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "ViaSeguraScript", "ViaSeguraScript.exe");
            

            if (!File.Exists(scriptPath))
            {
                throw new FileNotFoundException("Python script not found in scripts folder.");
            }
            //\"{scriptPath}\"
            ProcessStartInfo startInfo = new ProcessStartInfo
            {
                FileName = scriptPath,  // Use the bundled Python executable
                Arguments = $"{csvPath} {GetSelectedOptions()} {SelectedCam} {CrudHelper.dbCtx.Projects.Find(projectId).ProjectPath} {BatchSize}",  // Pass the script path and optional arguments
                UseShellExecute = false,  // No shell window
                RedirectStandardOutput = false,  // Capture output
                RedirectStandardError = true,   // Capture errors
                CreateNoWindow = false           // Run invisibly
            };
            Debug.WriteLine($"\"{scriptPath}\" {csvPath} {GetSelectedOptions()} {SelectedCam} {CrudHelper.dbCtx.Projects.Find(projectId).ProjectPath}");
            var tcs = new TaskCompletionSource<string>();

            try
            {
                using (Process process = new Process { StartInfo = startInfo, EnableRaisingEvents = true })
                {
                    


                    process.Exited += (sender, args) =>
                    {
                        if (process.ExitCode == 0)
                        {
                            var output = "Done";
                            //string output = process.StandardOutput.ReadToEnd();
                            tcs.TrySetResult(output);  // Successfully completed
                        }
                        else
                        {
                            string error = process.StandardError.ReadToEnd();
                            Log.Error(error,"Error in viasegura processing");
                            tcs.TrySetException(new Exception($"Python script failed with error: {error}"));
                        }

                        process.Dispose();
                    };

                    process.Start();
                    //process.BeginOutputReadLine();

                    // Await task completion or timeout
                    var completedTask = await Task.WhenAny(tcs.Task);

                    if (completedTask == tcs.Task)
                    {
                        Log.Debug(await tcs.Task);
                    }
                    else
                    {
                        process.Kill();  // Kill if timeout
                        throw new TimeoutException("Python script execution timed out.");
                    }
                }
            }
            catch (Exception ex)
            {
                Log.Error(ex,"Error ViaSegura in processing");
                Debug.WriteLine($"Error: {ex.Message}");  // Return error message
            }

        }

        private async Task ReadViaSeguraOutputAndUpdateCodings()
        {
            var csvPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData),
                "Pavesys", "tempViaSeguraResult.csv");

            var lines = File.ReadAllLines(csvPath);
            if (lines.Length <= 1) // Only header or empty
                return;

            var header = lines[0].Split(',');
            var codings = CrudHelper.dbCtx.Codings.Where(cod => cod.ProjectId == projectId).ToList();

            // Always start with first data line as previous line
            string[] previousLine = lines[1].Split(",");
            var csvLineIndex = 2; // Start from third line (after header and first data line)

            // Iterate through all codings
            for (int codingIndex = 0; codingIndex < codings.Count; codingIndex++)
            {
                string[] currentLine;

                if (codingsHasAllPhotos[codingIndex])
                {
                    // If this coding has a corresponding CSV line, use it
                    if (csvLineIndex < lines.Length)
                    {
                        currentLine = lines[csvLineIndex].Split(",");
                        previousLine = currentLine;
                        csvLineIndex++;
                    }
                    else
                    {
                        currentLine = previousLine;
                    }
                }
                else
                {
                    currentLine = previousLine;
                }

                for (int j = 0; j < currentLine.Length; j++)
                {
                    UpdateProperty(codings[codingIndex], header[j], currentLine[j]);
                }
            }

            await CrudHelper.dbCtx.SaveChangesAsync();
        }

        private async Task UpdateViaSeguraLabeledProjectField() {
            var projInDb = await CrudHelper.dbCtx.Projects.FindAsync(projectId);
            projInDb.ViaSeguraLabeled += GetSelectedOptions();
            await CrudHelper.dbCtx.SaveChangesAsync();
        }
        public async void Run() {
            try
            {
                IsNotUpdating = false;
                IsUpdating = true;
                var csvPath = await ProcessPhotosToCSV();
                await StartViaSeguraProcessing(csvPath);
                await ReadViaSeguraOutputAndUpdateCodings();
                await UpdateViaSeguraLabeledProjectField();
                IsNotUpdating = true;
                IsUpdating = false;
            }
            catch (Exception ex) 
            {
                IsNotUpdating = true;
                IsUpdating = false;
                Log.Error(ex, "Error in viasegura processing");
                await DialogHelper.ShowOkDialog("Error","", nonLocalizedContent: "Erro no processamento viasegura");
            }

        }


        static void UpdateProperty(Coding coding, string propertyName, string value)
        {
            switch (propertyName)
            {
                case "upgrade_cost":
                    coding.UpgradeCost = int.Parse(value) + 1;
                    break;
                case "service_road":
                    coding.ServiceRoad = int.Parse(value) + 1;
                    
                    break;
                case "delineation":
                    coding.Delineation = int.Parse(value) +1;
                    break;
                case "road_condition":
                    coding.RoadCondition = int.Parse(value) +1;
                    break;
                case "quality_of_curve":
                    coding.QualityCurve = int.Parse(value) + 1;
                    break;
                case "vehicle_parking":
                    coding.VehicleParking = int.Parse(value) switch { 
                        -1 => null,
                        1 => 1,
                        _ => null
                    };
                    break;
                case "property_access_points":
                    coding.PropertyAccessPoints = int.Parse(value) switch {
                        -1 => null,
                        1 => 4,
                        _ => null
                    };
                    break;
                case "skid_resistance":
                    coding.SkidResistanceGrip = int.Parse(value) + 1;
                    break;
                case "bicycle_facility":
                    //coding.BicycleFacility = int.Parse(value);
                    coding.BicycleFacility = null;
                    break;
                case "carriageway":
                    coding.CarriageWay = int.Parse(value) switch {
                        0 =>3, 
                        1 =>1,
                        _ => null

                    };
                    break;
                case "street_lighting":
                    coding.StreetLighting = int.Parse(value) +1;
                    break;
                case "speed_management":
                    coding.SpeedManagementTrafficCalming = int.Parse(value) + 1;
                    break;
                case "area_type":
                    coding.AreaType = int.Parse(value) +1;
                    break;
                case "land_use":
                    coding.LandUseDrivers= int.Parse(value) switch {
                        -1 => null,
                        0 => 3,
                        1 => 1,
                        4 => 4,
                        2 =>5,
                        _ => null

                    };
                    break;
                case "number_of_lanes":
                    coding.NumberLanes = int.Parse(value) + 1;
                    break;
                default:
                    break;
            }
        }

    }
}
