using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CarManagerV3
{
    /// <summary>
    /// Class <c>Car</c> represents a car with various attributes such as make, model, year, color, mileage, and price.
    /// </summary>
    public class Car
    {
        private int id;
        private string make;
        private string model;
        private int year;
        private string color;
        private int mileage;
        private decimal price;
        private int order;
        private int age;

        public int Id { get => id; 
            set {
                if (value < 0) throw new ArgumentException("Id cannot be negative.");
                id = value;
            } 
        }

        public string Make { get => make; 
            set
            {
                if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Make cannot be empty.");
                make = value;
            }
        }

        public string Model { get => model; 
            set
            {
                if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Model cannot be empty.");
                model = value;
            }
        }

        public int Year { get => year; 
            set
            {
                if (value < 1886 || value > DateTime.Now.Year + 1) throw new ArgumentException("Year must be between 1886 and next year.");
                year = value;
            }
        }

        public string Color { get => color; 
            set
            {
                if (string.IsNullOrWhiteSpace(value)) throw new ArgumentException("Color cannot be empty.");
                color = value;
            }
        }

        public int Mileage { get => mileage; 
            set
            {
                if (value < 0) throw new ArgumentException("Mileage cannot be negative.");
                mileage = value;
            }
        }

        public decimal Price { get => price; 
            set
            {
                if (value < 0) throw new ArgumentException("Price cannot be negative.");
                price = value;
            }
        }

        public int Order { get => order; set => order = value; }

        public int Age { get => DateTime.Now.Year - year; }
        public string AgeString
        {
            get
            {
                int age = this.Age;
                if (age == 0) return "New";
                else if (age == 1) return "1 year";
                else if (age < 0) return "From the future!";
                else return $"{age} years";
            }
        }

        //TODO: Make Id read-only CUID. Allows for better integrity, especially when merging.
        //TODO: Add buying price and automatic calculation of profit/loss with selling price suggestion.
        //TODO: Add Buying Date.
        //TODO: Add sold boolean and Sold Date.
        //TODO: Add "hidden" attribute for cars that are not for sale anymore but should be kept in the database for records.
        /// <summary>
        /// Initializes a new instance of the <see cref="Car"/> class.
        /// </summary>
        /// <param name="id">The unique identifier as an Integer.</param>
        /// <param name="make">The make / manufacturer of the car.</param>
        /// <param name="model">The model.</param>
        /// <param name="year">The year the car was built.</param>
        /// <param name="color">The color of the car.</param>
        /// <param name="mileage">The current mileage on the car.</param>
        /// <param name="price">The selling-price of the car.</param>
        /// <param name="order">The order.</param>
        public Car(int id, string make, string model, int year, string color, int mileage, decimal price, int order = 0)
        {
            // Sets the properties using the setters to ensure validation is applied.
            this.Id = id;
            this.Make = make;
            this.Model = model;
            this.Year = year;
            this.Color = color;
            this.Mileage = mileage;
            this.Price = price;
            this.Order = order;
        }


        /// <summary>
        /// Converts to string in a custom readable format.
        /// <example>
        /// For Example:
        /// Skoda Fabia (2015)
        /// </example>
        /// </summary>
        /// <returns>
        /// A <see cref="System.String" /> that represents this instance.
        /// </returns>
        public override string ToString()
        {
            return $"{this.Make} {this.Model} ({this.Year})";
        }

        /// <summary>
        /// Converts to default CSV savable string.
        /// </summary>
        /// <returns></returns>
        public string ToCsvString()
        {
            return $"{this.Id};{this.Make};{this.Model};{this.Year};{this.Color};{this.Mileage};{this.Price}";
        }

        //TODO: Add error handling for malformed CSV strings and detection for missing fields.
        //TODO: Add support for different CSV formats (e.g., different delimiters, quoted fields, etc.).
        //TODO: Add support for nil or optional fields.
        //TODO: Add detectin for invalid data / nonsensical values (e.g., negative mileage or year in the future). / Validate it actually is a car.
        /// <summary>
        /// Creates a <see cref="Car"/> instance from a CSV string in the default format.
        /// </summary>
        /// <param name="csv">The CSV Line.</param>
        /// <returns>
        /// A new <see cref="Car"/> instance.
        /// </returns>
        public static Car FromCsvString(string csv)
        {
            try
            {
                string[] parts = csv.Split(';');
                Car temp = new Car(int.Parse(parts[0]), parts[1], parts[2], int.Parse(parts[3]), parts[4], int.Parse(parts[5]), decimal.Parse(parts[6]));
                if (temp.Year < 1886 || temp.Year > DateTime.Now.Year + 1) throw new Exception($"Invalid year: {temp.Year}");
                if (temp.Mileage < 0) throw new Exception($"Mileage cannot be negative: {temp.Mileage}");
                if (temp.Price < 0) throw new Exception($"Price cannot be negative: {temp.Price}");
                return temp;
            }
            catch (Exception ex)
            {
                Console.Error.WriteLine($"Error parsing CSV Car string: {ex.Message}");
                return null;
            }
        }

        /// <summary>
        /// Determines whether this <see cref="Car"/> is any different from the provided <see cref="Car" />.
        /// </summary>
        /// <param name="other">The <see cref="Car"/> to check against</param>
        /// <returns>
        ///   <c>true</c> if the specified other is changed; otherwise, <c>false</c>.
        /// </returns>
        public bool IsChanged(Car other)
        {
            return this.Make != other.Make || this.Model != other.Model || this.Year != other.Year || this.Color != other.Color || this.Mileage != other.Mileage || this.Price != other.Price || this.Color != other.Color;
        }

        /// <summary>
        /// Clones this instance.
        /// </summary>
        /// <returns>An identical but seperate <see cref="Car"/></returns>
        public Car Clone()
        {
            return new Car(this.Id, this.Make, this.Model, this.Year, this.Color, this.Mileage, this.Price);
        }
    }
}
