using System;
using System.Collections.Generic;
using System.Linq;

using BS.Shared;
using BS.Shared.Core;
using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using BeWo.Data.Entities;
using BeWo.Data.Access;
using BS.Shared.DataContracts.Compact;

namespace BeWo.Report.ReportObjects
{
    public class ServiceInvoiceRO : AbstractBeWoReportObject<ServiceInvoiceRO>
    {
        public string AccountingPeriod { get; set; }

        public DateTime AccountingPeriodStart { get; set; }

        public DateTime AccountingPeriodEnd { get; set; }

        public string AmountAdvancedPayments { get; set; }

        public string AmountEquityContribution { get; set; }

        public string ApprovedAmountSum { get; set; }

        public string ApprovedBESum { get; set; }

        public string CreatorName { get; set; }

		public string CreatorDivision { get; set; }

		public long? CustomerOid { get; set; }

		public string CustomerFirstName { get; set; }

		public string CustomerLastName { get; set; }

        public string CustomerName { get; set; }

        public string CustomerReferenceNumber { get; set; }

        public string CustomerSalutation { get; set; }

		public string CustomerStreet { get; set; }

		public string CustomerPostalCode { get; set; }

		public string CustomerTown { get; set; }

		public DateTime? CustomerBirthdate { get; set; }

		public string DebitorNumber { get; set; }

		public string CustomerCostCenter { get; set; }

        public string GrossClaim { get; set; }

        public string InvoiceDate { get; set; }

		public string InvoiceId { get; set; }

		public DateTime? InvoiceDateTime { get; set; }

        public string InvoiceNumber { get; set; }

        public string NetClaim { get; set; }

        public string NotBillableNote { get; set; }

        public string Notice { get; set; }

        public string RecipientContactPerson { get; set; }

        public string RecipientDivision { get; set; }

        public string RecipientOrganisation { get; set; }

        public string RecipientPostCodeAndTown { get; set; }

        public string RecipientStreet { get; set; }

		public string RecipientPoBox { get; set; }

        public string SenderContactPerson { get; set; }

        public string SenderContactPersonDivision { get; set; }

        public string SenderContactPersonFax { get; set; }

        public string SenderContactPersonMail { get; set; }

        public string SenderContactPersonPhone { get; set; }

        public List<ServiceInvoicePeriodRO> ServiceInvoicePeriods { get; set; }

        public string ServiceUnitName { get; set; }
		
		public string OrganisationDebitorNumber { get; set; }

		public string OrganisationCostCenter { get; set; }

		public string ApprovalDate { get; set; }


        public static ServiceInvoiceRO Create(ServiceInvoiceDC pDC)
        {
            var lResult = new ServiceInvoiceRO
                {
					InvoiceId = pDC.InvoiceBase.InvoiceId,
                    InvoiceDate = String.Format("{0:dd.MM.yyyy}", pDC.InvoiceBase.InvoiceDate),
					InvoiceDateTime =  pDC.InvoiceBase.InvoiceDate,
                    InvoiceNumber = pDC.InvoiceBase.InvoiceNumber,
                    RecipientContactPerson = pDC.InvoiceBase.RecipientPersonFirstName.ToStringNullCheck()
                                             + " " +
                                             pDC.InvoiceBase.RecipientPersonLastName.ToStringNullCheck(),
                    RecipientDivision = pDC.InvoiceBase.RecipientDivision,
                    RecipientOrganisation = pDC.InvoiceBase.RecipientOrganisation,
                    RecipientPostCodeAndTown = pDC.InvoiceBase.RecipientPostCode + " " + pDC.InvoiceBase.RecipientTown,
                    RecipientStreet = pDC.InvoiceBase.RecipientStreet,
                    SenderContactPerson =
                        pDC.InvoiceBase.SenderFirstName.ToStringNullCheck() + " " +
                        pDC.InvoiceBase.SenderLastName.ToStringNullCheck(),
                    SenderContactPersonDivision = pDC.InvoiceBase.SenderDivision,
                };
	        if (String.IsNullOrWhiteSpace(lResult.RecipientContactPerson))
	        {
		        lResult.RecipientContactPerson = "";
	        }
            foreach (var iContactDC in pDC.InvoiceBase.SenderContactInformations)
            {
                if (iContactDC.ContactType == ContactType.business_Fax)
                {
                    lResult.SenderContactPersonFax = "Fax: " + iContactDC.ContactValue;
                }
                else if (iContactDC.ContactType == ContactType.business_Phone)
                {
                    lResult.SenderContactPersonPhone = "Tel.: " + iContactDC.ContactValue;
                }
                else if (iContactDC.ContactType == ContactType.business_Mail)
                {
                    lResult.SenderContactPersonMail = "E-Mail.: " + iContactDC.ContactValue;
                }
            }

			foreach (var iContactDC in pDC.InvoiceBase.RecipientContactInformations.Where(iContactDC => iContactDC.ContactType == ContactType.private_POBox))
			{
				lResult.RecipientPoBox = "Postfach " + iContactDC.ContactValue;
			}

	        lResult.CustomerOid = pDC.InvoiceBase.RecipientCustomerOid;
            lResult.CustomerReferenceNumber = pDC.InvoiceBase.CustomerReferenceNumber;
            lResult.CustomerName = pDC.InvoiceBase.CustomerFirstName + " " + pDC.InvoiceBase.CustomerLastName;
	        lResult.CustomerFirstName = pDC.InvoiceBase.CustomerFirstName;
			lResult.CustomerLastName = pDC.InvoiceBase.CustomerLastName;
			
	        long? customerOid = pDC.InvoiceBase.RecipientCustomerOid;

	        SupportConcept sc = null;
			if (pDC.InvoiceBase.SupportConceptOid.HasValue)
			{
				sc = DAOFactory.GenericDAO.GetByID<SupportConcept>(pDC.InvoiceBase.SupportConceptOid.Value);
			}

	        if (!customerOid.HasValue)
	        {
		        if (sc != null)
		        {
					customerOid = sc.Customer.Oid;
		        }
	        }
			if (customerOid.HasValue)
			{
				var customer = DAOFactory.GenericDAO.GetByID<Customer>(customerOid.Value);

				lResult.DebitorNumber = customer.DebitorNumber;
				lResult.CustomerCostCenter = customer.CostCenter;
				lResult.CustomerBirthdate = customer.Person.DateOfBirth;

				if (customer.Person.Address != null)
				{
					lResult.CustomerStreet = customer.Person.Address.Street;
					lResult.CustomerPostalCode = customer.Person.Address.PostalCode;
					lResult.CustomerTown = customer.Person.Address.Town;
				}

			}

            if (pDC.InvoiceBase.SupportConceptCostBearerRelDc != null)
            {
                lResult.CustomerSalutation = pDC.InvoiceBase.SupportConceptCostBearerRelDc.SupportConcept.Customer.Sex == Sex.Male
                                                 ? "Herr"
                                                 : "Frau";

				var org = pDC.InvoiceBase.SupportConceptCostBearerRelDc.CostBearer;
				lResult.OrganisationDebitorNumber = org.DebitorNumber;
				lResult.OrganisationCostCenter = org.CostCenter;
            }

            lResult.AccountingPeriod = String.Format("{0:dd.MM.yyyy}-{1:dd.MM.yyyy}", pDC.InvoiceBase.AccountingPeriodStart, pDC.InvoiceBase.AccountingPeriodEnd);

            lResult.AccountingPeriodStart = pDC.InvoiceBase.AccountingPeriodStart.Value;
            lResult.AccountingPeriodEnd = pDC.InvoiceBase.AccountingPeriodEnd.Value;

            if (pDC.ServiceUnit != null)
            {
                lResult.ServiceUnitName = pDC.ServiceUnit.UnitName;
            }

            lResult.ApprovedBESum = pDC.ServiceInvoicePeriods.Sum(i => i.ApprovedBE).Value.ToString("0.00");
            lResult.ApprovedAmountSum = pDC.ServiceInvoicePeriods.Sum(i => i.ApprovedAmountDefaultHourlyRate ?? i.ApprovedFixedAmount).Value.ToString("0.00 €");

            lResult.AmountAdvancedPayments = pDC.AmountAdvancePayments.HasValue ? pDC.AmountAdvancePayments.Value.ToString("0.00 €") : "-";

            lResult.AmountEquityContribution = pDC.AmountEquityContribution.HasValue ? pDC.AmountEquityContribution.Value.ToString("0.00 €") : "-";

            
            lResult.GrossClaim = (pDC.ClaimSum ?? 0m).ToString("0.00 €");
            lResult.NetClaim = (pDC.EndClaim ?? 0m).ToString("0.00 €"); 
            
            lResult.CreatorName = pDC.InvoiceBase.CreatorFirstName.ToStringNullCheck() + " "
                                  + pDC.InvoiceBase.CreatorLastName.ToStringNullCheck();

	        lResult.CreatorDivision = pDC.InvoiceBase.SenderDivision;

	        if (sc != null && sc.ApprovalDate.HasValue)
	        {
		        lResult.ApprovalDate = sc.ApprovalDate.Value.ToString("dd.MM.yyyy");
	        }

            lResult.Notice = pDC.InvoiceBase.Notice;

            var hoursNotBillableAbsence = pDC.ServiceInvoicePeriods.Sum(i => i.HoursNotBillableAbsence);
            var hoursNotBillableNotApproved = pDC.ServiceInvoicePeriods.Sum(i => i.HoursNotBillableNotApproved);

            if (hoursNotBillableAbsence == 0 && hoursNotBillableNotApproved == 0)
            {
                lResult.NotBillableNote = string.Empty;
            }
            else
            {
                var s = "Nicht abrechenbare geleistete Stunden im Zeitraum: ";
                if (hoursNotBillableAbsence > 0)
                {
                    s += string.Format("{0:0.00} (Klient abwesend) ", hoursNotBillableAbsence);
                    if (hoursNotBillableNotApproved > 0)
                    {
                        s += " + ";
                    }
                }

                if (hoursNotBillableNotApproved > 0)
                {
                    s += string.Format("{0:0.00} (nicht bewilligt) ", hoursNotBillableNotApproved);
                }

                lResult.NotBillableNote = s;
            }

            lResult.ServiceInvoicePeriods = pDC.ServiceInvoicePeriods.Select(i => ServiceInvoicePeriodRO.Create(pDC, i)).ToList();

            return lResult;
        }
	}

    public class ServiceInvoicePeriodRO
    {
        public string ApprovalPeriod { get; set; }

        public string ApprovedAmount { get; set; }

        public string ApprovedBE { get; set; }

        public decimal? ApprovedHours { get; set; }

        public string Claim { get; set; }

        public string NotBillableString { get; set; }

		public CompactCustomerDC Customer { get; set; }

		public CostBearer2SupportConcept CostBearer2SupportConcept { get; set; }

		public SupportConceptApprovalPeriod SupportConceptApprovalPeriod { get; set; }

        public List<ServiceInvoiceItemRO> ServiceInvoiceItems { get; set; }

        public static ServiceInvoicePeriodRO Create(ServiceInvoiceDC invoice, ServiceInvoicePeriodDC pDC)
        {
            var result = new ServiceInvoicePeriodRO
                {
                    ApprovalPeriod = new DateTimeSpan
                        {
                            StartDateTime = pDC.Start.Value,
                            EndDateTime = pDC.End.Value
                        }.ToDateString()
                };

            decimal amount = pDC.ApprovedAmountDefaultHourlyRate ?? (pDC.ApprovedFixedAmount ?? 0);
            result.ApprovedAmount = amount.ToString("0.00 €");

	        result.ApprovedBE = string.Empty;
	        if (pDC.ApprovedBE.HasValue)
	        {
				if (invoice.ServiceUnit != null)
					result.ApprovedBE = pDC.ApprovedBE.Value.ToString("(0.00 " + invoice.ServiceUnit.UnitName + ")");
				else
					result.ApprovedBE = pDC.ApprovedBE.Value.ToString("(0.00)");
	        }

            result.ApprovedHours = pDC.ApprovedHours;

            result.Claim = (pDC.Claim ?? 0m).ToString("0.00 €");
            result.NotBillableString = pDC.NotBillableString;

            result.ServiceInvoiceItems = pDC.InvoiceItems.Select(ServiceInvoiceItemRO.Create).ToList();

	        result.Customer = pDC.Customer;
	        
	        if (pDC.SupportConceptApprovalPeriod != null)
	        {
		        var scap =
			        DAOFactory.GenericDAO.GetByID<SupportConceptApprovalPeriod>(
				        pDC.SupportConceptApprovalPeriod.SupportConceptApprovalPeriodOid.Value);

		        result.SupportConceptApprovalPeriod = scap;
				result.CostBearer2SupportConcept = scap.CostBearer2SupportConcept;
	        }
			
	        return result;
        }
	}

    public class ServiceInvoiceItemRO
    {
        public string Duration { get; set; }

        public string GrossAmount { get; set; }

        public decimal? HourlyRate { get; set; }
		public string HourlyRateString { get; set; }

		public decimal? Hours { get; set; }

		public decimal? NetAmount { get; set; }

        public string RateFactor { get; set; }

        public string ServiceDescription { get; set; }

        public string CustomerFirstname { get; set; }

        public string CustomerLastname { get; set; }

        public DateTime? CustomerBirthdate { get; set; }

        public DateTime? AccountingPeriodStart { get; set; }

        public DateTime? AccountingPeriodEnd { get; set; }

		public string UnitDescription { get; set; }

        public string Notice { get; set; }
		
		public decimal? UnitCount { get; set; }
		public string UnitCountString { get; set; }

		public decimal? AmountPerUnit { get; set; }

		public ServiceRecordDC ServiceRecord { get; set; }

        public static ServiceInvoiceItemRO Create(InvoiceItemDC pDC)
        {
            var result = new ServiceInvoiceItemRO
            {
	            Duration = String.Format("{0:dd.MM.yy} - {1:dd.MM.yy}", 
				pDC.ItemPeriodStart, 
				pDC.ItemPeriodEnd), 
				GrossAmount = pDC.GrossAmountTotal.HasValue ? pDC.GrossAmountTotal.Value.ToString("0.00 €") : string.Empty, 
				HourlyRate = pDC.AmountPerUnit, 
				HourlyRateString = pDC.AmountPerUnit.HasValue ? pDC.AmountPerUnit.Value.ToString("0.00 €") : string.Empty, 
				Hours = pDC.UnitCount, 
				NetAmount = pDC.AmountTotal, 
				RateFactor = pDC.RateFactor.HasValue ? pDC.RateFactor.Value.ToString("0.00") + " %" : string.Empty, 
				ServiceDescription = pDC.ItemDescription, 
				AccountingPeriodStart = pDC.ItemPeriodStart, 
				AccountingPeriodEnd = pDC.ItemPeriodEnd, 
				UnitCount = pDC.UnitCount, 
				UnitCountString = pDC.UnitCount.HasValue ? pDC.UnitCount.Value.ToString("#.##") : string.Empty, 
				AmountPerUnit = pDC.AmountPerUnit, 
				UnitDescription = pDC.UnitDescription, 
				Notice = pDC.Notice,
				ServiceRecord = pDC.ServiceRecord
            };

	        if (pDC.SupportConceptApprovalPeriodOid.HasValue)
            {
                var ap = DAOFactory.GenericDAO.LoadByID<SupportConceptApprovalPeriod>(pDC.SupportConceptApprovalPeriodOid.Value);

	            try
	            {
					var c = ap.CostBearer2SupportConcept.SupportConcept.Customer;
					if (c != null)
					{
						result.CustomerFirstname = c.Person.FirstName;
						result.CustomerLastname = c.Person.LastName;
						result.CustomerBirthdate = c.Person.DateOfBirth;
					}
	            }
	            catch (Exception)
	            {
		            //ignore
	            }
                
            }

            return result;
        }

	}
}