using System.Collections.Generic;
using System.Linq;
using BS.Shared;
using System;

namespace BeWo.Data.Entities
{
    public class CostBearer : BeWoEntityBase
    {
        public static string PropertyName_ID = "ID";

        public static string PropertyName_CostRatePeriods = "CostRatePeriods";

        public static string PropertyName_HourlyRate = "HourlyRate";

        public static string PropertyName_IsCalculatingWithFactor = "IsCalculatingWithFactor";

        public static string PropertyName_IsSingleInvoicePerCustomer = "IsSingleInvoicePerCustomer";

        public static string PropertyName_MinutesIntervall = "MinutesIntervall";

        public static string PropertyName_Organisation = "Organisation";

        public static string PropertyName_RateFactor = "RateFactor";

        public static string PropertyName_ReferenceNumber = "ReferenceNumber";

        private string _ID;

        private IList<CostRatePeriod> _CostRatePeriods;

        private bool _IsCalculatingWithFactor;

        private bool _IsSingleInvoicePerCustomer;

        // private decimal? _HourlyRate;
        // private decimal? _RateFactor;
        private Organisation _Organisation;

        private string _ReferenceNumber;

        // private int? _MinutesIntervall;
        public CostBearer()
        {
            this._Tid = TableID.CostBearer;
        }

        public virtual string ID
        {
            get { return this._ID; }
            set
            {
                if (this.AreDifferent(this._ID, value))
                {
                    this._ID = value;
                }
            }
        }

        public virtual IList<CostRatePeriod> CostRatePeriods
        {
            get { return this._CostRatePeriods ?? (this._CostRatePeriods = new List<CostRatePeriod>()); }

            set
            {
                if (this.AreDifferent(this._CostRatePeriods, value))
                {
                    this._CostRatePeriods = value;
                }
            }
        }

        public virtual bool IsCalculatingWithFactor
        {
            get { return this._IsCalculatingWithFactor; }

            set
            {
                if (this.AreDifferent(this._IsCalculatingWithFactor, value))
                {
                    this._IsCalculatingWithFactor = value;
                }
            }
        }

        public virtual bool IsSingleInvoicePerCustomer
        {
            get { return this._IsSingleInvoicePerCustomer; }

            set
            {
                if (this.AreDifferent(this._IsSingleInvoicePerCustomer, value))
                {
                    this._IsSingleInvoicePerCustomer = value;
                }
            }
        }

        public virtual Organisation Organisation
        {
            get { return this._Organisation; }

            set
            {
                if (this.AreDifferent(this._Organisation, value))
                {
                    this._Organisation = value;
                }
            }
        }

        public virtual string ReferenceNumber
        {
            get { return this._ReferenceNumber; }

            set
            {
                if (this.AreDifferent(this._ReferenceNumber, value))
                {
                    this._ReferenceNumber = value;
                }
            }
        }

        public virtual CostRatePeriod GetCurrentlyValidRate(CostRatePeriodType type)
        {
            return GetCostRatePeriodForDate(type, DateTime.Now);
        }

        public virtual CostRatePeriod GetCurrentlyValidRate(CostRatePeriodType type,
            long? valueListEntry)
        {
            if (valueListEntry == null)
            {
                return GetCurrentlyValidRate(type);
            }

            var result = GetOldRates(type, valueListEntry).OrderBy(i => i.EndDate).FirstOrDefault(i => i.EndDate >= DateTime.Now.Date);

            return result ?? GetLatestRate(type, valueListEntry);
        }

        public virtual IList<CostRatePeriod> GetAllRatesNoValueListEntry(CostRatePeriodType type)
        {
            return CostRatePeriods
                .Where(i => i.ValueListEntry == null && i.CostRateType == type)
                .ToList();
        }

        public virtual CostRatePeriod GetLatestRate(CostRatePeriodType type)
        {
            return CostRatePeriods.SingleOrDefault(i => i.CostRateType == type && i.ValueListEntry == null && !i.EndDate.HasValue);
        }

        public virtual CostRatePeriod GetLatestRate(CostRatePeriodType type,
            long? valueListEntry)
        {
            if (valueListEntry == null)
            {
                return GetLatestRate(type);
            }

            return CostRatePeriods.SingleOrDefault(i => i.CostRateType == type && i.ValueListEntry != null
                && i.ValueListEntry.Oid.Equals(valueListEntry) && !i.EndDate.HasValue);
        }

        public virtual List<CostRatePeriod> GetOldRates(CostRatePeriodType type)
        {
            return new List<CostRatePeriod>(CostRatePeriods.Where(i => i.CostRateType == type && i.EndDate.HasValue && i.ValueListEntry == null).ToList());
        }

        public virtual List<CostRatePeriod> GetOldRates(CostRatePeriodType type,
            long? valueListEntry)
        {
            if (valueListEntry == null)
            {
                return GetOldRates(type);
            }

            return CostRatePeriods.Where(i => i.CostRateType == type && i.EndDate.HasValue && i.ValueListEntry != null &&
                        i.ValueListEntry.Oid.Equals(valueListEntry)).ToList();
        }

        public virtual CostRatePeriod GetCostRatePeriodForDate(CostRatePeriodType type, DateTime date)
        {
            var result = GetOldRates(type).OrderBy(i => i.EndDate).FirstOrDefault(i => i.EndDate >= date);

            return result ?? GetLatestRate(type);
        }

        public virtual CostRatePeriod GetCostRatePeriodForDate(
            CostRatePeriodType type, DateTime date, long valueListEntry)
        {
            var result = GetOldRates(type, valueListEntry).OrderBy(i => i.EndDate).FirstOrDefault(i => i.EndDate >= date);

            return result ?? GetLatestRate(type, valueListEntry);
        }

        public virtual Dictionary<long, CostRatePeriod> GetCostRatePeriodForDateGroupedByValueListEntryOid
            (CostRatePeriodType type, DateTime date)
        {
            return CostRatePeriods.Where(i => i.ValueListEntry != null).GroupBy(i => i.ValueListEntry.Oid.Value)
                   .ToDictionary(i => i.Key, i => GetCostRatePeriodForDate(type, date, i.Key));
        }
    }
}