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 LhCoburgPBInvoiceCreation : InvoiceCreation
	{
		private const String FAHRTKOSTEN_CATEGORY_NAME = "Fahrtkosten";
		private const decimal AMOUNT_PER_KM_DEFAULT = 0.35m;

		private ServiceCategory fahrtkostenServiceCategory = null;

		private DateTime? accountingPeriodStart = null;
		private DateTime? accountingPeriodEnd = null;

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


		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);
		}

		private ServiceCategory FahrtkostenServiceCategory
		{
			get
			{
				if (fahrtkostenServiceCategory == null)
				{
					fahrtkostenServiceCategory= DAOFactory.SearchDAO.FindServiceCategoryByName(FAHRTKOSTEN_CATEGORY_NAME);
				}
				return fahrtkostenServiceCategory;
			}
		}

		public override void SetRecipientInformation(ServiceInvoice serviceInvoice, CostBearer costBearer)
		{
			base.SetRecipientInformation(serviceInvoice, costBearer);

			if (serviceInvoice.InvoiceBase.CostBearer2SupportConcept != null &&
				serviceInvoice.InvoiceBase.CostBearer2SupportConcept.ApprovalPeriodList != null)
			{
				foreach (var ap in serviceInvoice.InvoiceBase.CostBearer2SupportConcept.ApprovalPeriodList)
				{
					if (ap.ServiceCategory != null && ap.ServiceCategory.Name.Trim() == "AUW Pers. Budget")
					{
						var c = serviceInvoice.InvoiceBase.CostBearer2SupportConcept.SupportConcept.Customer;

						serviceInvoice.InvoiceBase.RecipientOrganisation = "";
						serviceInvoice.InvoiceBase.RecipientPersonFirstName = c.Person.FirstName;
						serviceInvoice.InvoiceBase.RecipientPersonLastName = c.Person.LastName;
						serviceInvoice.InvoiceBase.RecipientAddress = c.Person.Address.CopyToNew();
					}
				}
			}
		}

		public override IList<InvoiceItem> CreateInvoiceItems(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap,
			Calculations calc)
		{
			var list = base.CreateInvoiceItems(serviceRecordsInPeriod, invoicePeriod, scap, calc);
			foreach (var invoiceItem in list)
			{
				if (invoiceItem.ItemDescription == "Assistent")
				{
					invoiceItem.ItemDescription = "Persönliche Assistenz";

				}
				else if (invoiceItem.ItemDescription == "Fachkraft")
				{
					invoiceItem.ItemDescription = "Fachkraft für ambulant unterstütztes Wohnen";}
			}
			list = list.OrderBy(ii => ii.ItemDescription).ToList();
			var fitems = CreateFahrtkostenItems(serviceRecordsInPeriod);

			list.AddRange(fitems);


			return CreateTaxiFahrtSummaryInvoiceItem(list, scap);
		}

		public override InvoiceItem CreateInvoiceItem(ServiceRecordDC sr, SupportConceptApprovalPeriod scap, Calculations calc)
		{
			if (sr.ServiceDescription.Name == "Taxifahrt")
			{
				var ii = new InvoiceItem();

				decimal fahrtkosten = 0;

				if (!String.IsNullOrEmpty(sr.Notice))
				{
					string pattern = @"[^,,^\d]";
					string replacement = "";
					var rgx = new Regex(pattern);
					string result = rgx.Replace(sr.Notice, replacement);

					Decimal.TryParse(result, out fahrtkosten);
				}
				ii.AmountPerUnit = fahrtkosten;
				ii.UnitCount = 1;
				ii.AmountTotal = fahrtkosten;
				ii.ItemPeriodStart = sr.Start;
				ii.ItemPeriodEnd = sr.End;
				ii.GrossAmountTotal = fahrtkosten;
				ii.AccountingInterval = AccountingIntervalType.FlatRate;
				ii.ItemDescription = sr.ServiceDescription.Name;
				ii.ServiceRecord = DAOFactory.GenericDAO.LoadByID<ServiceRecord>(sr.ServiceRecordOid.Value);
				if (scap != null)
					ii.SupportConceptApprovalPeriodOid = scap.Oid;

				return ii;
			}
			return base.CreateInvoiceItem(sr, scap, calc);
		}

		private IList<InvoiceItem> CreateFahrtkostenItems(List<ServiceRecordDC> serviceRecords)
		{
			
			Dictionary<String, InvoiceItem> mitarbeiter2Item = new Dictionary<String, InvoiceItem>();

			decimal amountPerKm = AMOUNT_PER_KM_DEFAULT;

			if (FahrtkostenServiceCategory != null)
			{
				
			}
			foreach (var sr in serviceRecords)
			{
				if (sr.DistanceInMeter.HasValue && sr.DistanceInMeter > 0)
				{
					String ma = sr.Employee.LastName;

					InvoiceItem ii = null;

					if (mitarbeiter2Item.ContainsKey(ma))
					{
						ii = mitarbeiter2Item[ma];
					}
					else
					{
						ii = new InvoiceItem();
						mitarbeiter2Item.Add(ma, ii);

						ii.UnitCount = 0;
						ii.ItemDescription = "Fahrtkosten";
						ii.UnitDescription = ma;
						ii.AmountPerUnit = amountPerKm;
						ii.ItemPeriodStart = accountingPeriodStart;
						ii.ItemPeriodEnd = accountingPeriodEnd;

					}
					ii.UnitCount += sr.DistanceInMeter;
				}
			}

			var list = mitarbeiter2Item.Values.ToList();
			foreach (var ii in list)
			{
				if (ii.AmountPerUnit.HasValue && ii.UnitCount.HasValue)
				{
					ii.AmountTotal = Math.Round(ii.AmountPerUnit.Value*ii.UnitCount.Value, 2, MidpointRounding.AwayFromZero);
					ii.GrossAmountTotal = ii.AmountTotal;
				}
			}
			return list;
		}

		public override void CheckMaxApprovedAmount(ServiceInvoice invoice, ServiceInvoicePeriod sip, SupportConceptApprovalPeriodDC scap,
			CostBearer2SupportConcept costBearer2SupportConcept, DateTimeSpan invoicePeriod, List<ServiceRecordDC> serviceRecords)
		{
			if (sip.ApprovedHours.HasValue && !scap.IsApprovedBEShifting)
			{
				decimal totalHours = 0;

				foreach (var ii in sip.InvoiceItemList.Where(ii => ii.UnitCount.HasValue))
				{
					if (totalHours + ii.UnitCount.Value > sip.ApprovedHours)
					{
						ii.UnitCount = sip.ApprovedHours.Value - totalHours;
						if (ii.AmountPerUnit.HasValue)
						{
							ii.AmountTotal = ii.AmountPerUnit.Value * ii.UnitCount;
							ii.GrossAmountTotal = ii.AmountTotal;
						}
						totalHours = sip.ApprovedHours.Value;
					}
					else
					{
						totalHours += ii.UnitCount.Value;
					}
				}
			}
		}

		public IList<InvoiceItem> CreateTaxiFahrtSummaryInvoiceItem(IList<InvoiceItem> itemList, SupportConceptApprovalPeriod scap)
		{
			var taxiItems = new List<InvoiceItem>();

			foreach (var ii in itemList)
			{
				if (ii.ItemDescription == "Taxifahrt")
				{
					taxiItems.Add(ii);
				}
			}

			if (taxiItems.Count > 0)
			{
				var taxiSummaryItem = new InvoiceItem();
				taxiSummaryItem.ItemDescription = "Auslagen für Taxifahrten";
				taxiSummaryItem.ItemPeriodStart = accountingPeriodStart;
				taxiSummaryItem.ItemPeriodEnd = accountingPeriodEnd;
				taxiSummaryItem.AmountTotal = 0;
				if (scap != null)
					taxiSummaryItem.SupportConceptApprovalPeriodOid = scap.Oid;

				foreach (var invoiceItem in taxiItems)
				{
					itemList.Remove(invoiceItem);
					taxiSummaryItem.AmountTotal += invoiceItem.AmountTotal;	
				}

				taxiSummaryItem.GrossAmountTotal = taxiSummaryItem.AmountTotal;

				itemList.Add(taxiSummaryItem);
			}
			return itemList;
		}
	}
}
