﻿namespace Dealership.Models
{
    using System.Collections.Generic;
    using System.Text;
    using Common;
    using Common.Enums;
    using Contracts;

    public abstract class Vehicle : IVehicle, ICommentable
    {
        private string make;
        private string model;
        private decimal price;
        private int wheels;

        protected Vehicle(string make, string model, decimal price, VehicleType type)
        {
            this.make = make;
            this.model = model;
            this.price = price;
            this.Type = type;
            this.wheels = (int)type;
            this.Comments = new List<IComment>();
        }

        public VehicleType Type { get; private set; }

        public int Wheels
        {
            get
            {
                return this.wheels;
            }

            private set
            {
                Validator.ValidateIntRange(
                    value,
                    Constants.MinWheels,
                    Constants.MaxWheels,
                    string.Format(
                        Constants.NumberMustBeBetweenMinAndMax,
                        Constants.Wheels,
                        Constants.MinWheels,
                        Constants.MaxWheels));

                this.wheels = value;
            }
        }

        public string Make
        {
            get
            {
                return this.make;
            }

            private set
            {
                Validator.ValidateNull(
                    value,
                    string.Format(Constants.PropertyCannotBeNull, Constants.Make));

                Validator.ValidateIntRange(
                    value.Length,
                    Constants.MinMakeLength,
                    Constants.MaxMakeLength,
                    string.Format(
                        Constants.StringMustBeBetweenMinAndMax,
                        Constants.Make,
                        Constants.MinMakeLength,
                        Constants.MaxMakeLength));

                this.make = value;
            }
        }

        public string Model
        {
            get
            {
                return this.model;
            }

            private set
            {
                Validator.ValidateNull(
                    value,
                    string.Format(Constants.PropertyCannotBeNull, Constants.Model));

                Validator.ValidateIntRange(
                    value.Length,
                    Constants.MinModelLength,
                    Constants.MaxModelLength,
                    string.Format(
                        Constants.StringMustBeBetweenMinAndMax,
                        Constants.Model,
                        Constants.MinModelLength,
                        Constants.MaxModelLength));

                this.model = value;
            }
        }

        public IList<IComment> Comments { get; private set; }

        public decimal Price
        {
            get
            {
                return this.price;
            }

            private set
            {
                Validator.ValidateDecimalRange(
                    value,
                    Constants.MinPrice,
                    Constants.MaxPrice,
                    string.Format(
                        Constants.NumberMustBeBetweenMinAndMax,
                        Constants.Price,
                        Constants.MinPrice,
                        Constants.MaxPrice));

                this.price = value;
            }
        }

        public override string ToString()
        {
            var sb = new StringBuilder();

            sb.AppendLine(string.Format("{0}:", this.GetType().Name));
            sb.AppendLine(string.Format("  {0}: {1}", Constants.Make, this.Make));
            sb.AppendLine(string.Format("  {0}: {1}", Constants.Model, this.Model));
            sb.AppendLine(string.Format("  {0}: {1}", Constants.Wheels, this.Wheels));
            sb.AppendLine(string.Format("  {0}: ${1}", Constants.Price, this.Price));
            sb.AppendLine(this.PrintAdditionalInfo());
            sb.AppendLine(this.PrintComments());

            return sb
                .ToString()
                .TrimEnd();
        }

        protected abstract string PrintAdditionalInfo();

        private string PrintComments()
        {
            var sb = new StringBuilder();

            if (this.Comments.Count <= 0)
            {
                sb.AppendLine(string.Format("{0}", Constants.NoCommentsHeader));
            }
            else
            {
                sb.AppendLine(string.Format("{0}", Constants.Comments));

                foreach (var comment in this.Comments)
                {
                    sb.AppendLine(comment.ToString());
                }

                sb.AppendLine(string.Format("{0}", Constants.Comments));
            }

            return sb
                .ToString()
                .TrimEnd();
        }
    }
}