using System;
using System.Collections.Generic;
using System.Linq;
using BeWo.Service.Plugins;
using BS.Shared;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.ServiceImplementations;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;

namespace BeWo.Report.ReportObjects
{
    public class ServiceRecordListRO : AbstractBeWoReportObject<ServiceRecordListRO>
    {
        private List<ServiceRecordDetail> _ServiceRecordDetailList = new List<ServiceRecordDetail>();

        public string CostBearer { get; set; }

        public string CustomerFirstName { get; set; }

        public string CustomerLastName { get; set; }

        public DateTime? ReportEndDate { get; set; }

        public DateTime? ReportStartDate { get; set; }

		public List<ServiceRecordStatistics> Statistics { get; set; }
		
        public List<ServiceRecordDetail> ServiceRecordDetailList
        {
            get
            {
                return this._ServiceRecordDetailList;
            }

            set
            {
                this._ServiceRecordDetailList = value;
            }
        }

        public DateTime? SupportConceptEndDate { get; set; }

        public DateTime? SupportConceptStartDate { get; set; }

		public static ServiceRecordListRO Create(long eOid, long cOid, long scOid, long cb2scOid, bool onlyAdditionalService, DateTimeSpan limitingTimeSpan)
        {
            // var pSpan = new DateTimeSpan();
            // pSpan.StartDateTime = new DateTime(pYear, pMonth, 1);
            // pSpan.EndDateTime = pSpan.StartDateTime.AddMonths(1).AddTicks(-1);
            var starttime = DateTime.Now.Ticks;

            var ro = new ServiceRecordListRO();
            IList<ServiceRecordDC> srList = null;

			var service = new OperationsServiceImp();
			
			var factory = PluginLoader.FindClass<ServiceRecordStatisticFactory>() ?? new ServiceRecordStatisticFactory();

	        if (cb2scOid > 0)
	        {
				var statistics = factory.CreateSupportConceptStatisticsImpl(cb2scOid, DateTime.Now);

		        ro.Statistics = new List<ServiceRecordStatistics>();

		        var header = new ServiceRecordStatistics
		        {
			        Text1 = "Bewilligungszeitraum:", 
					Text2 = "Geleistet diese Woche/Gesamt:", 
					Text3 = "Bewilligt pro Woche/Gesamt:", 
					Text4 = "Frei pro Woche(Ø)/Gesamt:"
		        };
		        ro.Statistics.Add(header);

		        if (statistics.PeriodStatistics.Count > 1 && !TimeSpanIsEqual(statistics))
			        ro.Statistics.Add(new ServiceRecordStatistics(statistics));
		        foreach (var dc in statistics.PeriodStatistics)
		        {
			        ro.Statistics.Add(new ServiceRecordStatistics(statistics, dc));
		        }
	        }
	        if (eOid != 0 && cOid == 0 && scOid == 0 && cb2scOid == 0)
            {
	            srList = service.GetEmployeesServiceRecordsInSpan(eOid, limitingTimeSpan);
            }
            else if (cOid != 0)
            {
             
                var cust = DAOFactory.GenericDAO.LoadByID<Customer>(cOid);

                ro.CustomerFirstName = cust.Person.FirstName;
                ro.CustomerLastName = cust.Person.LastName;

                if (cb2scOid != 0)
                {
                    var cb2sc = DAOFactory.GenericDAO.LoadByID<CostBearer2SupportConcept>(cb2scOid);

                    ro.SupportConceptStartDate = cb2sc.ApprovedStartDate ?? cb2sc.RequestedStartDate;

                    ro.SupportConceptStartDate = cb2sc.ApprovedEndDate ?? cb2sc.RequestedEndDate;

                    if (cb2sc.CostBearer != null && cb2sc.CostBearer.Organisation != null)
                    {
                        ro.CostBearer = cb2sc.CostBearer.Organisation.Name;
                    }
                }
				
	            var srList2 = service.FindServiceRecordsInSpan(cb2scOid, limitingTimeSpan);//service.GetCustomerServiceRecords(cOid, true);

                // Einschränkung wegen den ergänzenden Diensten; Es werden nur Einträge von ergänzenden Diensten angezeigt
                if (onlyAdditionalService)
                    srList2 = srList2.Where(dc => dc.ServiceRecordType == ServiceRecordTypeId.AdditionalService).ToList();

                srList = new List<ServiceRecordDC>();
                foreach (var item in srList2)
                {
                    bool add = true;

                    if (scOid != 0)
                    {
                        if (item.SupportConcept == null || item.SupportConcept.SupportConceptOid != scOid)
                        {
                            add = false;
                        }
                    }

                    if (add && cb2scOid != 0)
                    {
                        if (item.CostBearer2SupportConceptOid == null || item.CostBearer2SupportConceptOid.Value != cb2scOid)
                        {
                            add = false;
                        }
                    }

                    if (add)
                    {
                        srList.Add(item);
                    }
                }
            }

            if (srList != null)
            {
                srList = srList.OrderBy(sr => sr.Start).ToList();
            }

            foreach (var dc in srList)
            {
                var detail = new ServiceRecordDetail();
                if (dc.Employee != null)
                {
                    detail.EmployeeFirstName = dc.Employee.FirstName;
                    detail.EmployeeLastName = dc.Employee.LastName;
                }

                detail.Start = dc.Start;
                detail.End = dc.End;

                if (dc.Start != null && dc.Start.Value.Second == 0)
                {
                    detail.StartTime = dc.Start;

                    DateTime endDt = dc.Start.Value.AddMinutes((double)dc.RoundedDuration);

                    detail.EndTime = endDt;

                    detail.TimeRange = String.Format("{0:HH:mm} - {1:HH:mm}", detail.Start, endDt);
                }

                detail.InsertedOn = dc.InsertedOn;
                detail.InsUser = dc.InsUser;
                detail.Notice = dc.Notice;
                detail.RoundedDuration = dc.RoundedDuration;
	            detail.DistanceInMeter = dc.DistanceInMeter;

                if (detail.Start != null && detail.End != null)
                {
                    var ts = detail.End.Value.Subtract(detail.Start.Value);

                    detail.Duration = ts.GetTotalMinutes();
                }

                if (dc.ServiceDescription != null)
                {
                    detail.ServiceDescription = dc.ServiceDescription.Name;
                    detail.ServiceCategory = dc.ServiceDescription.CategoryName;
                }
	            detail.Goals = String.Empty;
				if (dc.Goals != null && dc.Goals.Count > 0)
				{
					
					foreach (var goal in dc.Goals)
					{
						if (detail.Goals.Length > 0)
							detail.Goals += ", ";
						detail.Goals += goal.TypeDescription;
					}
				}

                ro.ServiceRecordDetailList.Add(detail);
            }

            var endtime = DateTime.Now.Ticks;

            var diff = endtime - starttime;
            var secs = diff / (double)10000000;

            return ro;
        }

		private static bool TimeSpanIsEqual(SupportConceptStatisticsDC r)
		{
			if (r.PeriodStatistics != null && r.PeriodStatistics.Count > 1)
			{
				for (var i = 0; i < r.PeriodStatistics.Count - 1; i++)
				{
					var p1 = r.PeriodStatistics[i];

					if (p1.SupportConceptApprovalPeriod.StartDate.HasValue && p1.SupportConceptApprovalPeriod.EndDate.HasValue)
					{
						for (int j = i + 1; j < r.PeriodStatistics.Count; j++)
						{
							var p2 = r.PeriodStatistics[j];
							if (p2.SupportConceptApprovalPeriod.StartDate.HasValue && p2.SupportConceptApprovalPeriod.EndDate.HasValue)
							{
								if ((p1.SupportConceptApprovalPeriod.StartDate.Value.Date != p2.SupportConceptApprovalPeriod.StartDate.Value.Date) ||
									(p1.SupportConceptApprovalPeriod.EndDate.Value.Date != p2.SupportConceptApprovalPeriod.EndDate.Value.Date))
									return false;
							}
						}
					}
				}
			}
			return true;
		}

        public class ServiceRecordDetail
        {
            public decimal Duration { get; set; }

            public string EmployeeFirstName { get; set; }

            public string EmployeeLastName { get; set; }

            public DateTime? End { get; set; }

            public DateTime? EndTime { get; set; }

			public string Goals { get; set; }

            public string InsUser { get; set; }

            public DateTime? InsertedOn { get; set; }

            public string Notice { get; set; }

            public decimal RoundedDuration { get; set; }

            public string ServiceCategory { get; set; }

            public string ServiceDescription { get; set; }

            public DateTime? Start { get; set; }

            public DateTime? StartTime { get; set; }

            public string TimeRange { get; set; }

			public int? DistanceInMeter { get; set; }
        }

	    public class ServiceRecordStatistics
	    {
			public ServiceRecordStatistics()
			{
			}

		    public ServiceRecordStatistics(SupportConceptStatisticsDC dc)
		    {
				Text1 = "Gesamt";
			    BEApprovedTotal = dc.MinutesApprovedTotal/60;
			    BEApprovedPerMonth = dc.MinutesApprovedPerMonth/60;
			    BEApprovedPerWeek = dc.MinutesApprovedPerWeek/60;
			    BEProvidedTotal = dc.MinutesProvidedTotal/60;
			    BEProvidedTotalRounded = dc.MinutesProvidedTotalRounded/60;
			    BEProvidedThisWeek = dc.MinutesProvidedThisWeek/60;
			    BEProvidedThisMonth = dc.MinutesProvidedThisMonth/60;
			    BEFreePerWeek = dc.MinutesFreePerWeekAverage/60;
			    if (dc.MinutesOutOfApprovedPeriod > 0)
				    BEOutOfApprovedPeriod = String.Format("  {0:0.00}", dc.MinutesOutOfApprovedPeriod/60);

			    InitTextValues();
			}

		    public ServiceRecordStatistics(SupportConceptStatisticsDC stats, SupportConceptPeriodStatisticsDC periodStats)
		    {
			    if (periodStats.SupportConceptApprovalPeriod != null)
			    {
				    if (periodStats.SupportConceptApprovalPeriod.ServiceCategory != null)
				    {
					    if (periodStats.SupportConceptApprovalPeriod.StartDate.HasValue &&
					        periodStats.SupportConceptApprovalPeriod.EndDate.HasValue &&
					        periodStats.SupportConceptApprovalPeriod.StartDate.Value.Date == stats.StatisticsStartDate.Date &&
					        periodStats.SupportConceptApprovalPeriod.EndDate.Value.Date == stats.StatisticsEndDate.Date)
					    {
						    Text1 = periodStats.SupportConceptApprovalPeriod.ServiceCategory.Name;
					    }
					    else
					    {
							Text1 = String.Format("{0}: {1:dd.MM.yy} - {2:dd.MM.yy}",
						                                   periodStats.SupportConceptApprovalPeriod.ServiceCategory.Name,
						                                   periodStats.SupportConceptApprovalPeriod.StartDate,
						                                   periodStats.SupportConceptApprovalPeriod.EndDate);
					    }
				    }
				    else
				    {
						Text1 = String.Format("{0:dd.MM.yy} - {1:dd.MM.yy}",
					                                   periodStats.SupportConceptApprovalPeriod.StartDate,
					                                   periodStats.SupportConceptApprovalPeriod.EndDate);
				    }
			    }
			    BEApprovedTotal = periodStats.MinutesApprovedTotal/60;
			    BEApprovedPerMonth = periodStats.MinutesApprovedPerMonth/60;
			    BEApprovedPerWeek = periodStats.MinutesApprovedPerWeek/60;
			    BEProvidedTotal = periodStats.MinutesProvidedTotal/60;
			    BEProvidedTotalRounded = periodStats.MinutesProvidedTotalRounded/60;
			    BEProvidedThisWeek = periodStats.MinutesProvidedThisWeek/60;
			    BEProvidedThisMonth = periodStats.MinutesProvidedThisMonth/60;
			    BEFreePerWeek = periodStats.MinutesFreePerWeek/60;
			    
				InitTextValues();
		    }

			private void InitTextValues()
			{
				Text2 = String.Format("{0:0.00}          {1:0.00}", BEProvidedThisWeek, BEProvidedTotalRounded);
			
				Text3 = String.Format("{0:0.00}          {1:0.00}", BEApprovedPerWeek, BEApprovedTotal);

				Text4 = String.Format("{0:0.00}          {1:0.00}", BEFreePerWeek, BEFreeTotal);
			}


		    public String Text1 { get; set; }

			public String Text2 { get; set; }

			public String Text3 { get; set; }

			public String Text4 { get; set; }


		    public decimal BEProvidedTotal { get; set; }

		    public decimal BEProvidedTotalRounded { get; set; }

		    public decimal BEProvidedThisWeek { get; set; }

		    public decimal BEProvidedThisMonth { get; set; }

		    public decimal BEApprovedTotal { get; set; }

		    public decimal BEApprovedPerWeek { get; set; }

		    public decimal BEApprovedPerMonth { get; set; }

		    public decimal BEFreePerWeek { get; set; }

		    public String BEOutOfApprovedPeriod { get; set; }

		    public decimal BEFreeTotal
		    {
			    get { return BEApprovedTotal - BEProvidedTotalRounded; }
		    }

	    }
    }
}