using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BeWo.Data.Access;
using BeWo.Data.Entities;
using BeWo.Service.DCEntityMapper;
using BeWo.Service.Invoicing;
using BeWo.Service.Plugins;
using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using BS.Shared.Services;

namespace BeWo.GpzBiberachReports.Invoicing
{
	[IDSpecificClass(Identifiers = new string[] { "ABW" })]
	public class 
		GpzBiberachAbwInvoiceCreation : InvoiceCreation
	{
		private const String ABW_SERVICE_CATEGORY_NAME = "ABW";

		private Dictionary<String, bool> pauschalenImMonat = new Dictionary<string, bool>();

		public override void SetInvoiceId(ServiceInvoice invoice)
		{
			invoice.InvoiceBase.InvoiceId = "ABW";
			invoice.InvoiceBase.InvoiceTypeText = "Ambulant Betreutes Wohnen";
		}

		public override ServiceInvoicePeriod CreateServiceInvoicePeriod(SupportConceptApprovalPeriodDC approvalPeriodDC, DateTimeSpan invoiceAccountingPeriodSpan)
		{
			var period = base.CreateServiceInvoicePeriod(approvalPeriodDC, invoiceAccountingPeriodSpan);
			if (period.Start.HasValue)
				period.Start = new DateTime(period.Start.Value.Year, period.Start.Value.Month, 1);

			if (period.End.HasValue)
				period.End = new DateTime(period.End.Value.Year, period.End.Value.Month, 1).AddMonths(1).AddDays(-1); 
			return period;
		}

		public override void SetInvoiceItems(ServiceInvoice invoice,
											ServiceInvoicePeriod serviceInvoicePeriod,
											SupportConceptApprovalPeriodDC supportConceptApprovalPeriod,
											CostBearer2SupportConcept cb2sc,
											DateTimeSpan invoicePeriod,
											List<ServiceRecordDC> serviceRecords)
		{
			var calc = PluginLoader.FindClass<Calculations>(_SpecificID) ?? Calculations.GetInstance(_SpecificID);

			
			var serviceRecordsInPeriod = serviceRecords.Where(
				i =>
				{
					bool valid = i.Start.Value.InBetween(serviceInvoicePeriod.Start.Value,
															serviceInvoicePeriod.End.Value, true);

					if (valid && serviceInvoicePeriod.SupportConceptApprovalPeriod != null && serviceInvoicePeriod.SupportConceptApprovalPeriod.ServiceCategory != null)
						valid = serviceInvoicePeriod.SupportConceptApprovalPeriod.ServiceCategory.Oid ==
								i.ServiceDescription.Category.ServiceCategoryOid;
					return valid;
				}).ToList();

			if (serviceRecordsInPeriod.Count > 0)
			{
				//var approvalPeriodDC = DAOFactory.GenericDAO
				//    .LoadByID<SupportConceptApprovalPeriod>(serviceInvoicePeriod.SupportConceptApprovalPeriodOid.Value)
				//    .MapToNewDC();

				serviceInvoicePeriod.HoursNotBillableAbsence +=
					calc.GetHoursNotBillableDueToAbsenceTimes(supportConceptApprovalPeriod,
																cb2sc.CostBearer.CostRatePeriods.MapToNewDCs(),
																serviceRecordsInPeriod,
																cb2sc.SupportConcept.Customer.GetAbsencesTimesNotBillableWholeWeeks(),
																true, true);

				serviceInvoicePeriod.HoursNotBillableNotApproved +=
					calc.GetHoursNotBillableDueToMoreThanApproved(supportConceptApprovalPeriod,
																	cb2sc.CostBearer.CostRatePeriods.MapToNewDCs(),
																	serviceRecordsInPeriod,
																	true, true);

				IList<InvoiceItem> itemList = CreateInvoiceItems(serviceRecordsInPeriod, invoicePeriod, serviceInvoicePeriod.SupportConceptApprovalPeriod, calc);
				serviceInvoicePeriod.InvoiceItemList.AddRange(itemList);

			}

			String categoryName = null;
			if (supportConceptApprovalPeriod.ServiceCategory != null)
			{
				categoryName = supportConceptApprovalPeriod.ServiceCategory.Name;
			}


			DateTime? pauschaleStart = serviceInvoicePeriod.Start;
			DateTime? pauschaleEnd = serviceInvoicePeriod.End;

			if (serviceInvoicePeriod.Start.HasValue && serviceInvoicePeriod.End.HasValue)
			{
				DateTime start = serviceInvoicePeriod.Start.Value;
				DateTime end = serviceInvoicePeriod.End.Value;


				while (start < end)
				{
					String key = String.Format("{0:yyyyMM}", start);

					if (pauschalenImMonat.ContainsKey(key))
					{
						pauschaleStart = start.AddMonths(1);
					}
					start = start.AddMonths(1);
				}
				
			}


			if (pauschaleStart.HasValue && pauschaleEnd.HasValue && pauschaleStart.Value < pauschaleEnd.Value)
			{
				IList<BillingData> data = calc.GetFixedBillingData(supportConceptApprovalPeriod, pauschaleStart, pauschaleEnd);
				if (categoryName == "ABW +" && (data == null || data.Count == 0))
				{
					data = CreateABWPauschale(supportConceptApprovalPeriod, pauschaleStart, pauschaleEnd);
				}
				foreach (var billingData in data)
				{
					var pauschale = new InvoiceItem
					{
						AmountTotal = billingData.AmountTotal,
						GrossAmountTotal = billingData.GrossAmountTotal,
						ItemPeriodStart = billingData.BillingPeriodStart,
						ItemPeriodEnd = billingData.BillingPeriodEnd,
						AccountingInterval = billingData.AccountingInterval,
						AmountPerUnit = billingData.AmountPerUnit,
						UnitCount = billingData.UnitCount,
						ItemDescription = "Monatliche Pauschale"
					};
					if (!String.IsNullOrEmpty(categoryName) && !categoryName.ToLower().Contains("abw"))
					{
						pauschale.ItemDescription = categoryName;
					}

					if (pauschale.ItemPeriodStart.HasValue && pauschale.ItemPeriodEnd.HasValue)
					{
						DateTime start = pauschale.ItemPeriodStart.Value;
						DateTime end = pauschale.ItemPeriodEnd.Value;

						while (start < end)
						{
							String key = String.Format("{0:yyyyMM}", start);

							if (!pauschalenImMonat.ContainsKey(key))
							{
								pauschalenImMonat.Add(key, true);
							}
							start = start.AddMonths(1);
						}
					}

					serviceInvoicePeriod.InvoiceItemList.Add(pauschale);
				}
			}
		}

		private IList<BillingData> CreateABWPauschale(SupportConceptApprovalPeriodDC supportConceptApprovalPeriod, DateTime? start, DateTime? end)
		{
			IList<BillingData> billingDatas = new List<BillingData>();
			DateTime? dtStart = start ?? supportConceptApprovalPeriod.StartDate;
			DateTime? dtEnd = end ?? supportConceptApprovalPeriod.EndDate;

			if (dtStart.HasValue && dtEnd.HasValue)
			{
				ServiceCategory cat = DAOFactory.SearchDAO.FindServiceCategoryByName(ABW_SERVICE_CATEGORY_NAME);
				
				if (cat != null)
				{
					var crpList = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(cat.CostRatePeriods);
					var ai = cat.AccountingInterval;
					if (ai.HasValue)
					{
						DateTime intervalStart = dtStart.Value;
						DateTime intervalEnd = dtStart.Value;
						while (intervalStart < dtEnd)
						{

							switch (ai.Value)
							{
								case AccountingIntervalType.Daily:
									intervalEnd = intervalStart.AddDays(1);
									break;
								case AccountingIntervalType.Weekly:
									intervalEnd = intervalStart.AddDays(7);
									break;
								case AccountingIntervalType.Fortnightly:
									intervalEnd = intervalStart.AddDays(14);
									break;
								case AccountingIntervalType.Monthly:
									intervalEnd = intervalStart.AddMonths(1);
									break;
								case AccountingIntervalType.Quarterly:
									intervalEnd = intervalStart.AddMonths(3);
									break;
								case AccountingIntervalType.HalfYearly:
									intervalEnd = intervalStart.AddMonths(6);
									break;
								case AccountingIntervalType.Yearly:
									intervalEnd = intervalStart.AddYears(1);
									break;
								case AccountingIntervalType.FlatRate:
									intervalEnd = dtEnd.Value;
									break;
								default:
									intervalEnd = dtEnd.Value;
									break;

							}

							CostRatePeriodDC crp = crpList.GetCostRatePeriodForDate(CostRatePeriodType.AmountOfMoney,
																					intervalStart);
							if (crp != null && crp.CostRateValue.HasValue)
							{
								billingDatas.Add(new BillingData()
								{
									AmountTotal = crp.CostRateValue,
									GrossAmountTotal = crp.CostRateValue,
									BillingPeriodStart = intervalStart,
									BillingPeriodEnd = intervalEnd.AddDays(-1),
									AccountingInterval = ai

								});
							}

							intervalStart = intervalEnd;
						}
					}
				}
			}


			return billingDatas;
		}

		public override IList<InvoiceItem> CreateSummaryInvoiceItems(IList<InvoiceItem> itemList, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap,
			Calculations calc)
		{
			return itemList;
		}
    }
}
