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 BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.DataContracts.Compact;
using BS.Shared.Extensions;
using BS.Shared.Services;

namespace BeWo.GpzBiberachReports.Invoicing
{
	[IDSpecificClass(Identifiers = new string[] { "PersoenlichesBudget" })]
	public class GpzBiberachPBInvoiceCreation : InvoiceCreation
	{
		private const String PB_SERVICE_CATEGORY_NAME = "Persönliches Budget";
		private const String PB_SERVICE_DESCRIPTION_NAME = "Persönliches Budget Grundpauschale";

		private const decimal AMOUNT_PER_KM = 0.3m;

		
		public override void SetInvoiceId(ServiceInvoice invoice)
		{
			invoice.InvoiceBase.InvoiceId = "PersoenlichesBudget";
			invoice.InvoiceBase.InvoiceTypeText = "Persönliches Budget";
		}

		public override IList<InvoiceItem> CreateInvoiceItems(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
		{
			List<InvoiceItem> list = new List<InvoiceItem>();
			foreach (var iServiceRecord in serviceRecordsInPeriod)
			{
				if (iServiceRecord.ServiceDescription.Category.IsBillable)
				{
					if (!iServiceRecord.AlreadyAccounted)
					{
						InvoiceItem invoiceItem = CreateInvoiceItem(iServiceRecord, scap, calc);
						if (invoiceItem != null)
						{
							list.Add(invoiceItem);
						}
						iServiceRecord.AlreadyAccounted = true;
					}
				}
			}

			var list2 = CreateSummaryInvoiceItems(list, invoicePeriod, scap, calc);

			InvoiceItem ttii = CreateMonatlichePauschaleInvoiceItem(invoicePeriod, scap, calc);
			if (ttii != null)
				list2.Add(ttii);

			return list2;
		}

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

		public override InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc)
		{
			//if (iServiceRecord.DistanceInMeter.HasValue && iServiceRecord.DistanceInMeter.Value > 0)
			//{
			//	var invoiceItem = new InvoiceItem();

			//	var bd = calc.GetBillingData(iServiceRecord);

			//	invoiceItem.AmountPerUnit = bd.AmountPerUnit;
			//	invoiceItem.UnitCount = bd.UnitCount;
			//	invoiceItem.AmountTotal = bd.AmountTotal;
			//	invoiceItem.ItemPeriodStart = bd.BillingPeriodStart;
			//	invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd;
			//	invoiceItem.RateFactor = bd.RateFactor;
			//	invoiceItem.GrossAmountTotal = bd.GrossAmountTotal;
			//	invoiceItem.AccountingInterval = bd.AccountingInterval;
			//	invoiceItem.ItemDescription = iServiceRecord.ServiceDescription.Name; //iServiceRecord.Employee + " - " + iServiceRecord.ServiceDescription.Name;
			//	invoiceItem.ServiceRecord = DAOFactory.GenericDAO.LoadByID<ServiceRecord>(iServiceRecord.ServiceRecordOid.Value);
			//	if (scap != null)
			//		invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid;

				
			//	return invoiceItem;
			//}
			var item = base.CreateInvoiceItem(iServiceRecord, scap, calc);
			if (item.ItemDescription.Contains("Grundpauschale"))
			{
				return null;
			}
			else
			{
				item.ItemDescription = "Persönliches Budget";	
			}
			
			if (iServiceRecord.DistanceInMeter.HasValue && iServiceRecord.DistanceInMeter > 0)
			{
				item.GrossAmountTotal += (iServiceRecord.DistanceInMeter * AMOUNT_PER_KM);
			}
			item.UnitCount = item.UnitCount*60;
			if ((item.GrossAmountTotal == null || item.GrossAmountTotal.Value == 0) &&
			    (item.UnitCount == null || item.UnitCount.Value == 0))
			{
				return null;
			}
			return item;
		}

		private InvoiceItem CreateMonatlichePauschaleInvoiceItem(DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
		{
			var invoiceItem = new InvoiceItem();
			invoiceItem.ItemDescription = "Monatliche Pauschale";
			invoiceItem.AmountTotal = 0;
			invoiceItem.GrossAmountTotal = 0;
			invoiceItem.UnitCount = 0;

			var data = CreatePBPauschale(invoicePeriod);
			
			foreach (var billingData in data)
			{
				invoiceItem.AmountTotal += billingData.AmountTotal;
				invoiceItem.GrossAmountTotal += billingData.GrossAmountTotal;
				invoiceItem.UnitCount += billingData.UnitCount;

				invoiceItem.AccountingInterval = billingData.AccountingInterval;
				invoiceItem.AmountPerUnit = billingData.AmountPerUnit;

				if (invoiceItem.ItemPeriodStart == null || invoiceItem.ItemPeriodStart > billingData.BillingPeriodStart)
				{
					invoiceItem.ItemPeriodStart = billingData.BillingPeriodStart;
				}

				if (invoiceItem.ItemPeriodEnd == null || invoiceItem.ItemPeriodEnd < billingData.BillingPeriodEnd)
				{
					invoiceItem.ItemPeriodEnd = billingData.BillingPeriodEnd;
				}

			}

			if (scap != null)
				invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid;


			return invoiceItem;
		}

		private IList<BillingData> CreatePBPauschale(DateTimeSpan invoicePeriod)
		{
			IList<BillingData> billingDatas = new List<BillingData>();
			
			ServiceCategory cat = DAOFactory.SearchDAO.FindServiceCategoryByName(PB_SERVICE_CATEGORY_NAME);

			
			if (cat != null)
			{
				ServiceDescription sdPauschale = null;
				var dList = DAOFactory.SearchDAO.FindServiceDescriptionForCategory(cat.Oid.Value);
				foreach (var d in dList)
				{
					if (d.Name == PB_SERVICE_DESCRIPTION_NAME)
					{
						sdPauschale = d;
					}
				}

				if (sdPauschale != null)
				{
					var crpList = MapperFactory.CostRatePeriodDC_CostRatePeriod.MapToNewDCs(sdPauschale.CostRatePeriods);
					var ai = sdPauschale.AccountingInterval;

					if (ai.HasValue)
					{

						DateTime intervalStart = invoicePeriod.StartDate;
						DateTime intervalEnd = invoicePeriod.StartDate;
						while (intervalStart < invoicePeriod.EndDate)
						{

							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 = invoicePeriod.EndDate;
									break;
								default:
									intervalEnd = invoicePeriod.EndDate;
									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;
		}

    }
}
