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

using BeWo.Data.Access;
using BeWo.Data.Entities;

using BS.Shared.DataContracts;
using BS.Shared.Extensions;
using BS.Shared;

namespace BeWo.Report.ReportObjects
{
    public class Settlement2RO : AbstractBeWoReportObject<Settlement2RO>
    {
        public DateTime? AbsenceEndDate1 { get; set; }

        public DateTime? AbsenceEndDate2 { get; set; }

        public DateTime? AbsenceEndDate3 { get; set; }

        public DateTime? AbsenceEndDate4 { get; set; }

        public string AbsenceReason1 { get; set; }

        public string AbsenceReason2 { get; set; }

        public string AbsenceReason3 { get; set; }

        public string AbsenceReason4 { get; set; }

        public DateTime? AbsenceStartDate1 { get; set; }

        public DateTime? AbsenceStartDate2 { get; set; }

        public DateTime? AbsenceStartDate3 { get; set; }

        public DateTime? AbsenceStartDate4 { get; set; }

        public string AbsenceTimes { get; set; }

        public DateTime AccountingEndDate { get; set; }

        public DateTime AccountingStartDate { get; set; }

        public string AccountingPeriod { get; set; }

        public decimal AmountAdvancedPayments { get; set; }

        public decimal AmountBillableTotal { get; set; }
        
        public decimal ApprovedFLSTotal { get; set; }

        public String ApprovedFLS { get; set; }

        public String ApprovedFLSWithFactor { get; set; }

        public decimal ApprovedFLSWeekly { get; set; }

        public decimal Claim { get; set; }

        public decimal? Eigenbeteiligung { get; set; }

        public decimal RecordedFLS { get; set; }

        public string CreatorName { get; set; }

        public DateTime? ApprovalNoticeDate { get; set; }
        
        public DateTime? CustomerBirthday { get; set; }

        public string CustomerFirstName { get; set; }

        public string CustomerLastName { get; set; }

        public string CustomerReferenceNumber { get; set; }

        public string CustomerReferenceNumberAndDate { get; set; }

        public string DebitorNumber { get; set; }

        public string CostCenter { get; set; }

        public string FinalSentence { get; set; }

        public DateTime InvoiceDate { get; set; }

        public string InvoiceNumber { get; set; }

        public string Notice { get; set; }

        public double RateFactor { get; set; }

        public string RateFactorText2 { get; set; }

        public string RecipientContactPerson { get; set; }

        public string RecipientDivision { get; set; }

        public string RecipientOrganisation { get; set; }

        public String RecipientPostBox { get; set; }

        public string RecipientPostCodeAndTown { get; set; }

        public string RecipientStreet { get; set; }

        public string RecipientPhone { get; set; }

        public string RecipientFax { get; set; }

        public string Salutation1 { get; set; }

        public string Salutation2 { 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 decimal? WeeksInAccountingPeriod { get; set; }

		public DateTime? TerminationDate { get; set; }

		public String TerminationReason { get; set; }
		
        public List<SettlementInvoiceItemRO> InvoiceItems { get; set; }

        public class SettlementInvoiceItemRO
        {
            public DateTime? PeriodStartDate { get; set; }

            public DateTime? PeriodEndDate { get; set; }

            public decimal? AmountPerUnit { get; set; }

            public decimal? AmountTotal { get; set; }

            public decimal? GrossAmountTotal { get; set; }

            public string ItemDescription { get; set; }

            public string DetailDescription { get; set; }

            public decimal? RateFactor { get; set; }

            public decimal? UnitCount { get; set; }

            public string UnitDescription { get; set; }

            public decimal ReceivedAmount { get; set; }

            public decimal? MaxApprovedUnitCount { get; set; }

            public decimal? ApprovedPerUnit { get; set; }

            public AccountingIntervalType? ApprovalUnit { get; set; }

            public decimal? MaxApprovedAmount { get; set; }

            public string AbrechnungsText { get; set; }
        }


        public static Settlement2RO Create(Settlement2DC pDC)
        {
            var lResult = new Settlement2RO();

            CostBearer2SupportConcept lCb2Sc = DAOFactory.GenericDAO.LoadByID<CostBearer2SupportConcept>(pDC.CostBearer2SupportConceptOid.Value);
            Customer lCustomer = lCb2Sc.SupportConcept.Customer;

            lResult.AccountingStartDate = pDC.AccountingPeriodStart.Value;
            lResult.AccountingEndDate = pDC.AccountingPeriodEnd.Value;
            lResult.AccountingPeriod = String.Format("{0:dd.MM.yyyy}", pDC.AccountingPeriodStart.Value) + " bis " + String.Format("{0:dd.MM.yyyy}", pDC.AccountingPeriodEnd.Value);

            double days = pDC.AccountingPeriodEnd.Value.Subtract(pDC.AccountingPeriodStart.Value).TotalDays + 1;
            lResult.WeeksInAccountingPeriod = (decimal)(days / 7);

            lResult.CreatorName = pDC.CreatorFirstName + " " + pDC.CreatorLastName;
            lResult.Salutation1 = lCustomer.Person.Sex == Sex.Male ? "Herr" : "Frau";
            lResult.Salutation2 = lCustomer.Person.Sex == Sex.Male ? "Herrn" : "Frau";

            lResult.Eigenbeteiligung = pDC.EquityContribution;

            if (pDC.ApprovedFLSWeekly != null)
            {
                lResult.ApprovedFLSWeekly = pDC.ApprovedFLSWeekly.Value;
            }

            lResult.ApprovedFLSTotal = pDC.ApprovedFLS ?? 0;
            lResult.ApprovedFLS = String.Format("{0:0.00} FLS", lResult.ApprovedFLSTotal);


            lResult.ApprovedFLSWeekly = Math.Round(lResult.ApprovedFLSWeekly, 2, MidpointRounding.AwayFromZero);

            lResult.AmountAdvancedPayments = pDC.AmountAdvancedPayments ?? 0;
            lResult.AmountBillableTotal = pDC.AmountBillableTotal ?? 0;
            
            double fact = 1;
            lResult.RateFactor = 1;
			
	        if ((!pDC.RateFactor.HasValue || pDC.RateFactor.Value == 1) && pDC.InvoiceItems != null)
	        {
		        foreach (var ii in pDC.InvoiceItems)
		        {
			        if (ii.RateFactor.HasValue && !pDC.RateFactor.HasValue)
			        {
						pDC.RateFactor = ii.RateFactor.Value;
			        }
			        if (ii.UnitCount.HasValue)
			        {
				        lResult.RecordedFLS += ii.UnitCount.Value;
			        }
		        }
	        }
            if (pDC.RateFactor != null && pDC.RateFactor.Value > 0 )
            {
                fact = (100 + (double) pDC.RateFactor.Value)/100;
                lResult.RateFactor = fact;
                lResult.RateFactorText2 = Math.Round(fact, 2, MidpointRounding.AwayFromZero).ToString();
                lResult.ApprovedFLSWithFactor = string.Format("{0:0.00} FLS", pDC.ApprovedFLS*(decimal) fact);
            }
            
            
            lResult.Claim = pDC.Claim ?? 0;

            if (pDC.Claim > 0)
            {
                lResult.FinalSentence = "Bitte überweisen Sie unsere Restforderung nach Prüfung der Schlussabrechnung auf das unten angegebene Konto.";
            }
            else if (pDC.Claim == 0)
            {
                lResult.FinalSentence = "Alle Ansprüche sind ausgeglichen.";
            }
            else if (pDC.Claim < 0)
            {
                lResult.FinalSentence = "Die geleistete Überzahlung wird in den nächsten Tagen ihrem Konto gutgeschrieben.";
            }


            lResult.DebitorNumber = lCustomer.DebitorNumber;
            lResult.CostCenter    = lCustomer.CostCenter;

            lResult.CustomerFirstName              = lCustomer.Person.FirstName;
            lResult.CustomerLastName               = lCustomer.Person.LastName;
            lResult.CustomerBirthday               = lCustomer.Person.DateOfBirth;
            lResult.CustomerReferenceNumber        = pDC.CustomerReferenceNumber;
            lResult.CustomerReferenceNumberAndDate = "Az.: " + pDC.CustomerReferenceNumber;
			lResult.TerminationDate                = lResult.TerminationDate;
			lResult.TerminationReason              = lResult.TerminationReason;

            if (pDC.ApprovalNoticeDate != null)
            {
                lResult.ApprovalNoticeDate = pDC.ApprovalNoticeDate.Value;
                lResult.CustomerReferenceNumberAndDate += " - Bewilligungsbescheid vom " + String.Format("{0:dd.MM.yyyy}", pDC.ApprovalNoticeDate);
            }

            lResult.InvoiceDate   = pDC.InvoiceDate.Value;
            lResult.InvoiceNumber = pDC.InvoiceNumber;
            lResult.Notice        = String.IsNullOrEmpty(pDC.Notice) ? pDC.Notice : pDC.Notice.Replace("\r\n", "\n");


            lResult.RecipientContactPerson   = pDC.RecipientContactPerson;
            lResult.RecipientDivision        = pDC.RecipientDivision;
            lResult.RecipientOrganisation    = pDC.RecipientOrganisation;
            lResult.RecipientPostBox         = pDC.RecipientPostBox;
            lResult.RecipientPostCodeAndTown = pDC.RecipientPostCode + " " + pDC.RecipientTown;
            lResult.RecipientStreet          = pDC.RecipientStreet;
            
            Organisation org = lCb2Sc.CostBearer.Organisation;
            if (org != null)
            {
                if (org.Contacts != null)
                {
                    var contact =
                        org.Contacts.FirstOrDefault(con => con.Type == ContactType.business_Fax);

                    if (contact != null)
                        lResult.RecipientFax = contact.Value;

                    contact =
                        org.Contacts.FirstOrDefault(con => con.Type == ContactType.business_Phone);

                    if (contact != null)
                        lResult.RecipientPhone = contact.Value;
                }
            }

            lResult.SenderContactPerson = pDC.SenderContactPersonFirstName + " " + pDC.SenderContactPersonLastName;
            lResult.SenderContactPersonDivision = pDC.SenderContactPersonDivision;
            if (!pDC.SenderContactPersonFax.IsNullOrEmpty())
            {
                lResult.SenderContactPersonFax = "Fax: " + pDC.SenderContactPersonFax;
            }

            if (!pDC.SenderContactPersonMail.IsNullOrEmpty())
            {
                lResult.SenderContactPersonMail = "Email: " + pDC.SenderContactPersonMail;
            }

            if (!pDC.SenderContactPersonPhone.IsNullOrEmpty())
            {
                lResult.SenderContactPersonPhone = "Tel.: " + pDC.SenderContactPersonPhone;
            }

            CreateInvoiceItems(lResult, pDC);
            CreateAbsenceTimes(lResult, lCustomer, pDC);


            return lResult;
        }

        private static void CreateInvoiceItems(Settlement2RO lResult, Settlement2DC pDC)
        {
            lResult.InvoiceItems = new List<SettlementInvoiceItemRO>();
            if (pDC.InvoiceItems != null)
            {
                foreach (var ii in pDC.InvoiceItems)
                {
                    SettlementInvoiceItemRO iiRo = new SettlementInvoiceItemRO();
                    iiRo.AmountPerUnit           = ii.AmountPerUnit;
                    iiRo.AmountTotal             = ii.AmountTotal;
                    iiRo.GrossAmountTotal        = ii.GrossAmountTotal;
                    iiRo.ItemDescription         = ii.ItemDescription;
                    iiRo.MaxApprovedAmount       = ii.MaxApprovedAmount;
                    iiRo.MaxApprovedUnitCount    = ii.MaxApprovedUnitCount;
                    iiRo.ApprovedPerUnit         = ii.ApprovedPerUnit;
                    iiRo.ApprovalUnit            = ii.ApprovalUnit;
                    iiRo.PeriodEndDate           = ii.ItemPeriodEnd;
                    iiRo.PeriodStartDate         = ii.ItemPeriodStart;
                    iiRo.RateFactor              = ii.RateFactor;
                    iiRo.ReceivedAmount          = ii.ReceivedAmount;
                    iiRo.UnitCount               = ii.UnitCount;
                    iiRo.UnitDescription         = ii.UnitDescription;

                    if (iiRo.PeriodStartDate > lResult.AccountingStartDate || iiRo.PeriodEndDate < lResult.AccountingEndDate)
                    {
                        iiRo.DetailDescription =
                            String.Format("{0} vom {1:dd.MM.yyyy} bis {2:dd.MM.yyyy}: {3:0.##} x {4:c}",
                                          iiRo.ItemDescription,
                                          iiRo.PeriodStartDate,
                                          iiRo.PeriodEndDate,
                                          iiRo.UnitCount,
                                          iiRo.AmountPerUnit);
                    }
                    else
                    {
                        iiRo.DetailDescription =
                            String.Format("{0}: {1:0.##} x {2:c}",
                                          iiRo.ItemDescription,
                                          iiRo.UnitCount,
                                          iiRo.AmountPerUnit);
                    }
                    if (iiRo.RateFactor.HasValue && iiRo.RateFactor.Value != 0)
                    {
                        iiRo.DetailDescription += String.Format(" x {0:0.##}", (iiRo.RateFactor + 100)/100);
                    }

                    iiRo.AbrechnungsText = String.Format("{0:dd.MM.yyyy} bis {1:dd.MM.yyyy}: {2:0.##} FLS {3}x {4:c}",
                        iiRo.PeriodStartDate, iiRo.PeriodEndDate, iiRo.UnitCount, !iiRo.RateFactor.HasValue ? "" : String.Format("x {0:0.00} ", (iiRo.RateFactor + 100) /100), iiRo.AmountPerUnit);

                    lResult.InvoiceItems.Add(iiRo);
                }
            }
        }

        private static void CreateAbsenceTimes(Settlement2RO lResult, Customer lCustomer, Settlement2DC pDC)
        {
            lResult.AbsenceTimes = string.Empty;

            if (lCustomer.AbsenceTimes != null)
            {
                StringBuilder sb = new StringBuilder();

                int count = 1;

                foreach (AbsenceTime at in lCustomer.AbsenceTimes)
                {
                    if (at.AbsenceSpan != null)
                    {
                        bool cont = true;

                        if (at.Start != null && at.Start > pDC.AccountingPeriodEnd)
                        {
                            cont = false;
                        }

                        if (cont && at.End != null && at.End < pDC.AccountingPeriodStart)
                        {
                            cont = false;
                        }

                        if (cont)
                        {
                            if (sb.Length > 0)
                            {
                                sb.Append(", ");
                            }

                            if (at.Start.HasValue)
                            {
                                if (count == 1)
                                {
                                    lResult.AbsenceStartDate1 = at.Start.Value;
                                }

                                if (count == 2)
                                {
                                    lResult.AbsenceStartDate2 = at.Start.Value;
                                }

                                if (count == 3)
                                {
                                    lResult.AbsenceStartDate3 = at.Start.Value;
                                }

                                if (count == 4)
                                {
                                    lResult.AbsenceStartDate4 = at.Start.Value;
                                }

                                sb.Append(string.Format("{0:00}", at.Start.Value.Day));
                                sb.Append(".");
                                sb.Append(string.Format("{0:00}", at.Start.Value.Month));
                                sb.Append(".");
                                sb.Append(at.Start.Value.Year.ToString().Substring(2));

                                if (at.End.HasValue)
                                {
                                    if (count == 1)
                                    {
                                        lResult.AbsenceEndDate1 = at.End.Value;
                                    }

                                    if (count == 2)
                                    {
                                        lResult.AbsenceEndDate2 = at.End.Value;
                                    }

                                    if (count == 3)
                                    {
                                        lResult.AbsenceEndDate3 = at.End.Value;
                                    }

                                    if (count == 4)
                                    {
                                        lResult.AbsenceEndDate4 = at.End.Value;
                                    }

                                    sb.Append(" - ");
                                    sb.Append(string.Format("{0:00}", at.End.Value.Day));
                                    sb.Append(".");
                                    sb.Append(string.Format("{0:00}", at.End.Value.Month));
                                    sb.Append(".");
                                    sb.Append(at.End.Value.Year.ToString().Substring(2));
                                }

                                if (at.AbsenceReason != null)
                                {
                                    if (count == 1)
                                    {
                                        lResult.AbsenceReason1 = at.AbsenceReason.Description;
                                    }

                                    if (count == 2)
                                    {
                                        lResult.AbsenceReason2 = at.AbsenceReason.Description;
                                    }

                                    if (count == 3)
                                    {
                                        lResult.AbsenceReason3 = at.AbsenceReason.Description;
                                    }

                                    if (count == 4)
                                    {
                                        lResult.AbsenceReason4 = at.AbsenceReason.Description;
                                    }
                                }
                            }

                            sb.Append(" ");
                            sb.Append(at.AbsenceReason.Description);

                            count++;
                        }
                    }
                }

                if (sb.Length > 0)
                {
                    lResult.AbsenceTimes = "Abwesenheitszeiten: " + sb;
                }
            }
        }
    }
}