﻿namespace Cosmetics.Models.Abstract
{
    using System;
    using System.Text;
    using Common;
    using Contracts;

    public abstract class Product : IProduct
    {
        private const int MinNameLength = 3;
        private const int MaxNameLength = 10;
        private const int MinBrandLength = 2;
        private const int MaxBrandLength = 10;
        private const string ProductName = "Product name";
        private const string ProductBrand = "Product brand";

        private string name;
        private string brand;

        /// <summary>
        /// Initializes a new instance of the <see cref="Product"/> class.
        /// </summary>
        /// <param name="name">Product name.</param>
        /// <param name="brand">Product brand.</param>
        /// <param name="price">Product price.</param>
        /// <param name="gender">Product gender.</param>
        protected Product(string name, string brand, decimal price, GenderType gender)
        {
            this.Name = name;
            this.Brand = brand;
            this.Price = price;
            this.Gender = gender;
        }
        
        /// <summary>
        /// Product name.
        /// </summary>
        /// <exception cref="NullReferenceException"/>
        /// <exception cref="IndexOutOfRangeException"/>
        public string Name
        {
            get
            {
                return this.name;
            }

            private set
            {
                Validator.CheckIfStringIsNullOrEmpty(
                    value,
                    string.Format(GlobalErrorMessages.StringCannotBeNullOrEmpty, ProductName));

                Validator.CheckIfStringLengthIsValid(
                    value,
                    MaxNameLength,
                    MinNameLength,
                    string.Format(
                        GlobalErrorMessages.InvalidStringLength,
                        ProductName,
                        MinNameLength,
                        MaxNameLength));

                this.name = value;
            }
        }

        /// <summary>
        /// Product brand.
        /// </summary>
        /// <exception cref="NullReferenceException"/>
        /// <exception cref="IndexOutOfRangeException"/>
        public string Brand
        {
            get
            {
                return this.brand;
            }

            private set
            {
                Validator.CheckIfStringIsNullOrEmpty(
                    value,
                    string.Format(GlobalErrorMessages.StringCannotBeNullOrEmpty, ProductBrand));

                Validator.CheckIfStringLengthIsValid(
                    value,
                    MaxNameLength,
                    MinBrandLength,
                    string.Format(
                        GlobalErrorMessages.InvalidStringLength,
                        ProductBrand,
                        MinBrandLength,
                        MaxBrandLength));

                this.brand = value;
            }
        }

        /// <summary>
        /// Product price.
        /// </summary>
        public decimal Price { get; protected set; }

        /// <summary>
        /// Product gedner type.
        /// </summary>
        public GenderType Gender { get; protected set; }

        /// <summary>
        /// A text in appropriate form represents the information of the product.
        /// </summary>
        /// <returns>A string represents the information about the product.</returns>
        public virtual string Print()
        {
            var sb = new StringBuilder();

            sb.AppendLine(string.Format("- {0} - {1}:", this.Brand, this.Name));
            sb.AppendLine(string.Format("  * Price: ${0}", this.Price));
            sb.Append(string.Format("  * For gender: {0}", this.Gender));

            return sb.ToString();
        }
    }
}