using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;


namespace CarManagerV3
{
    /// <summary>
    /// Handles safe reading and writing of car data to files.
    /// </summary>
    internal class SafeManager
    {
        /// <summary>
        /// The path of the txt file that contains recently opened file paths.
        /// </summary>
        private static string recentPathsFile = Properties.Settings.Default.DataLocation + "\\recent_paths.txt";


        /// <summary>
        /// Initializes a file at a specified path if it does not already exist.
        /// </summary>
        /// <param name="path">The path of the file.</param>
        public static void InitializeFile(string path)
        {
            try
            {
                if (!File.Exists(@path))
                {
                    using (StreamWriter writer = new StreamWriter(@path))
                    {
                        // Create the file, empty
                        //writer.WriteLine();
                        writer.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error initializing file: {ex.Message}");
            }
        }

        /// <summary>
        /// Initializes a file and its parent folders at a specified path if they do not already exist.
        /// </summary>
        /// <param name="path">The path of the file.</param>
        public static void initializeFileAndFolders(string path, bool folderOnly = false)
        {
            try
            {
                string directory = Path.GetDirectoryName(path);
                Console.WriteLine($"Initializing file and folders for path: {path}");
                if (!Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
                if(!folderOnly) InitializeFile(path);
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error initializing file and folders: {ex.Message}");
            }
        }

        /// <summary>
        /// Ensures the directory exists.
        /// </summary>
        /// <param name="path">The path.</param>
        public static void EnsureDirectoryExists(string path)
        {
            try
            {
                string directory = Path.GetDirectoryName(path);
                if (directory != null && !Directory.Exists(directory))
                {
                    Directory.CreateDirectory(directory);
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error ensuring directory exists: {ex.Message}");
            }
        }

        /// <summary>
        /// Reads cars from a specified file path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <returns>
        /// A <see cref="List{Car}"/> containing the cars read from the file.
        /// </returns>
        public static List<Car> ReadCars(string path)
        {
            List<Car> cars = new List<Car>();
            List<string> failedLines = new List<string>();
            bool isLegacy = false;
            try
            {
                using (StreamReader reader = new StreamReader(@path))
                {
                    string line;
                    while ((line = reader.ReadLine()) != null)
                    {
                        // Process the line
                        if (line == "") continue;
                        if (Car.isLegacyCsvString(line))
                        {
                            if (!StateManager.askForMigration())
                            {
                                MessageBox.Show("The file you are trying to open is in an old format that is no longer supported. Please select a different file.", "Unsupported Format", MessageBoxButtons.OK, MessageBoxIcon.Error);
                                throw new LegacyException();
                                //Environment.Exit(0);
                            }
                            else
                            {
                                isLegacy = true;
                            }
                        }
                        Car tmp = Car.FromCsvString(line);
                        if (tmp == null)
                        {
                            failedLines.Add(line);
                            continue;
                        }
                        cars.Add(tmp);
                    }
                    reader.Close();
                }
            }
            catch (LegacyException ex)
            {
                throw ex;
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error reading cars from file: {ex.Message}");
            }
            if (failedLines.Count > 0)
            {
                Console.Error.WriteLine($"Warning: {failedLines.Count} lines could not be parsed and were skipped.");
                foreach (string failedLine in failedLines)
                {
                    Console.Error.WriteLine($"Failed line: {failedLine}");
                }
                MessageBox.Show($"Warning: {failedLines.Count} lines in the file could not be parsed and were skipped. Check the console for details.", "Parsing Warning", MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }
            cars = StateManager.normalizeOrders(cars);
            cars = cars.OrderBy(c => c.Order).ToList();
            if (isLegacy)
            {
                SafeManager.SaveCars(path, cars);
            }
            return cars;
        }

        /// <summary>
        /// Saves the cars to a specified file path.
        /// </summary>
        /// <param name="path">The path.</param>
        /// <param name="cars">A <see cref="List{Car}"/> containing all cars to save.</param>
        public static void SaveCars(string path, List<Car> cars)
        {
            try
            {
                using (StreamWriter writer = new StreamWriter(@path))
                {
                    foreach (Car car in cars)
                    {
                        writer.WriteLine(car.ToCsvString());
                    }
                    writer.Close();
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error saving cars to file: {ex.Message}");
                MessageBox.Show($"Error saving cars to file: {ex.Message}", "Save Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Adds a file path to the recent paths list.
        /// If a path is already in the list, it is moved to the top.
        /// Otherwise, it is added to the top.
        /// Keeps only the 5 most recent paths.
        /// </summary>
        /// <param name="path">The path.</param>
        public static void AddRecentPath(string path)
        {
            List<string> paths = new List<string>();
            try
            {
                paths = GetRecentPaths();
                paths.Remove(path);
                paths.Insert(0, path);
                if (paths.Count > 5)
                {
                    paths = paths.Take(5).ToList();
                }
                using (StreamWriter writer = new StreamWriter(recentPathsFile))
                {
                    foreach (string p in paths)
                    {
                        writer.WriteLine(p);
                    }
                    writer.Close();
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error managing recent paths: {ex.Message}");
            }
        }

        /// <summary>
        /// Gets the recently opened file paths.
        /// </summary>
        /// <returns>
        /// A <see cref="List{String}"/> containing the recent file paths.
        /// </returns>
        public static List<string> GetRecentPaths()
        {
            List<string> paths = new List<string>();
            try
            {
                recentPathsFile = Properties.Settings.Default.DataLocation + "\\recent_paths.txt";
                initializeFileAndFolders(recentPathsFile);
                if (File.Exists(recentPathsFile)) //TODO: Remove
                {
                    using (StreamReader reader = new StreamReader(recentPathsFile))
                    {
                        string line;
                        while ((line = reader.ReadLine()) != null)
                        {
                            paths.Add(line);
                        }
                        reader.Close();
                    }
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error reading recent paths: {ex.Message}");
            }
            return paths;
        }

        /// <summary>
        /// Gets the folder of the most recently opened file.
        /// </summary>
        /// <returns>
        /// The folder path of the most recently opened file, or the users documents folder if no recent files.
        /// </returns>
        public static string getRecentFolder()
        {
            List<string> recentPaths = GetRecentPaths();
            if (recentPaths.Count > 0)
            {
                string recentFile = recentPaths[0];
                if (File.Exists(recentFile))
                {
                    return Path.GetDirectoryName(recentFile);
                }
            }
            return Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
        }

        /// <summary>
        /// Clears the recently opened file paths list by deleting the recent paths file.
        /// </summary>
        public static void ClearRecentPaths()
        {
            try
            {
                if (File.Exists(recentPathsFile))
                {
                    File.Delete(recentPathsFile);
                }
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error clearing recent paths: {ex.Message}");
            }
        }

    }
}
