using System;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms.VisualStyles;
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.DataContracts.Compact;
using BS.Shared.Extensions;
using BS.Shared.Services;

namespace LebenshilfeCoburg.Invoicing
{
	public class LhCoburgAusbildungsassistenzInvoiceCreation : InvoiceCreation
	{
		private DateTime? accountingPeriodStart = null;
		private DateTime? accountingPeriodEnd = null;

		public override void SetInvoiceId(ServiceInvoice invoice)
		{
			invoice.InvoiceBase.InvoiceId = "Ausbildungsassistenz";
			invoice.InvoiceBase.InvoiceTypeText = "Ausbildungsassistenz";
		}


		public override void SetInvoiceBaseData(int invoiceCounter, ServiceInvoice invoice, CostBearer costBearer, DateTimeSpan invoicePeriod,
			IList<CompactSupportConceptDC> supportConceptList)
		{
			if (invoicePeriod != null)
			{
				accountingPeriodStart = invoicePeriod.StartDate;
				accountingPeriodEnd = invoicePeriod.EndDate;
			}
			base.SetInvoiceBaseData(invoiceCounter, invoice, costBearer, invoicePeriod, supportConceptList);
		}

		public override void SetServiceInvoicePeriods(ServiceInvoice invoice, CostBearer2SupportConcept costBearer2SupportConcept,
			DateTimeSpan invoicePeriod, List<ServiceRecordDC> serviceRecords)
		{
			base.SetServiceInvoicePeriods(invoice, costBearer2SupportConcept, invoicePeriod, serviceRecords);


			if (invoice.ServiceInvoicePeriodList != null && accountingPeriodStart.HasValue && accountingPeriodEnd.HasValue)
			{
				var newPeriodList = new List<ServiceInvoicePeriod>();

				DateTime startMonth = accountingPeriodStart.Value;

				while (startMonth < accountingPeriodEnd.Value)
				{
					DateTime endMonth = new DateTime(startMonth.Year, startMonth.Month, 1).AddMonths(1).AddDays(-1);
					if (endMonth > accountingPeriodEnd.Value)
					{
						endMonth = accountingPeriodEnd.Value;
					}

					var newSip = new ServiceInvoicePeriod();
					newSip.Start = startMonth;
					newSip.End = endMonth;
					
					newPeriodList.Add(newSip);

					endMonth = endMonth.AddDays(1);
					foreach (var sip in invoice.ServiceInvoicePeriodList)
					{
						foreach (var ii in sip.InvoiceItemList)
						{
							if (ii.ItemPeriodStart >= startMonth && ii.ItemPeriodEnd < endMonth)
							{
								newSip.InvoiceItemList.Add(ii);
							}
						}
					}
					startMonth = endMonth;
				}

				foreach (var sip in newPeriodList)
				{
					CreateSummaryInvoiceItems(sip);

					var item = CreateAbschlagItem(sip, costBearer2SupportConcept);

					if (item != null)
					{
						sip.InvoiceItemList.Add(item);
					}
				}
				invoice.ServiceInvoicePeriodList = newPeriodList;
			}
		}

		private InvoiceItem CreateAbschlagItem(ServiceInvoicePeriod sip, CostBearer2SupportConcept c2s)
		{
			var ii = new InvoiceItem();
			ii.ItemDescription = "Abschlag";
			ii.ItemPeriodStart = sip.Start;
			ii.ItemPeriodEnd = sip.End;
			ii.AmountTotal = 0;

			var processedBookings = new Dictionary<long, bool>();
			IList<AccountingTransaction> bookingList = c2s.AccountingTransactions;

			bookingList = bookingList.Where(i => i.BookingDate.HasValue
													&& i.BookingDate.Value.InBetween(sip.Start.Value, sip.End.Value, true)).ToList();

			foreach (AccountingTransaction item in bookingList)
			{
				if (!processedBookings.ContainsKey(item.Oid.Value))
				{
					ii.AmountTotal -= item.Amount;
					processedBookings.Add(item.Oid.Value, true);
				}
			}


			ii.GrossAmountTotal = ii.AmountTotal;
			if (ii.AmountTotal != 0)
			{
				return ii;
			}
			return null;
		}

		private void CreateSummaryInvoiceItems(ServiceInvoicePeriod sip)
		{
			//Fasse InvoiceItems mit gleichem Stundensatz zusammen:

			var newlist = new List<InvoiceItem>();

			var rateToItem = new Dictionary<String, InvoiceItem>();
			foreach (InvoiceItem iitem in sip.InvoiceItemList)
			{
				InvoiceItem item;
				String key = String.Format("{0}_{1}_{2}", iitem.ItemDescription, iitem.AmountPerUnit, iitem.RateFactor);

				if (rateToItem.ContainsKey(key))
				{
					item = rateToItem[key];
				}
				else
				{
					item = new InvoiceItem();
					newlist.Add(item);

					item.AmountPerUnit = iitem.AmountPerUnit;
					item.ItemPeriodStart = sip.Start;
					item.ItemPeriodEnd = sip.End;
					item.RateFactor = iitem.RateFactor;
					item.UnitCount = 0;

					item.AccountingInterval = iitem.AccountingInterval;
					item.ItemDescription = iitem.ItemDescription;
					
					rateToItem[key] = item;
				}

				item.UnitCount += iitem.UnitCount ?? 0;
			}


			foreach (InvoiceItem invoiceItem in newlist)
			{
				if (invoiceItem.AmountPerUnit.HasValue)
				{
					invoiceItem.AmountPerUnit = Math.Round(invoiceItem.AmountPerUnit.Value, 2, MidpointRounding.AwayFromZero);
				}
				else
				{
					invoiceItem.AmountPerUnit = 0;
				}

				if (invoiceItem.UnitCount.HasValue)
				{
					invoiceItem.UnitCount = Math.Round(invoiceItem.UnitCount.Value, 2, MidpointRounding.AwayFromZero);
				}
				else
				{
					invoiceItem.UnitCount = 0;
				}

				invoiceItem.AmountTotal = invoiceItem.AmountPerUnit * invoiceItem.UnitCount;
				invoiceItem.AmountTotal = Math.Round(invoiceItem.AmountTotal.Value, 2, MidpointRounding.AwayFromZero);

				if (invoiceItem.RateFactor.HasValue)
				{
					invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal * ((invoiceItem.RateFactor + 100) / 100);
				}
				else
				{
					invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal;
				}
			}
			sip.InvoiceItemList = newlist;
		}

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