using System;
using System.Collections.Generic;
using System.Linq;
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 FibMarburg.Invoicing
{
    public class FibMarburgDefaultInvoiceCreation : InvoiceCreation
    {
        private DateTime? accountingPeriodStart = null;
        private DateTime? accountingPeriodEnd = null;

        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 IList<InvoiceItem> CreateInvoiceItems(List<ServiceRecordDC> serviceRecordsInPeriod, DateTimeSpan invoicePeriod, SupportConceptApprovalPeriod scap, Calculations calc)
        {
            if (!accountingPeriodStart.HasValue)
                accountingPeriodStart = scap.StartDate;
            if (!accountingPeriodEnd.HasValue)
                accountingPeriodEnd = scap.EndDate;


            var absenceTimes = scap.CostBearer2SupportConcept.SupportConcept.Customer.AbsenceTimes;
            bool hasAbsenceTime = HasAbsenceTimeInMonth(absenceTimes, accountingPeriodStart.Value);

            var itemList = new List<InvoiceItem>();
            var invoiceItem = new InvoiceItem();

            var crpList = scap.CostBearer2SupportConcept.CostBearer.CostRatePeriods.MapToNewDCs();

            decimal hourlyRate = 0;
            if (accountingPeriodStart.HasValue)
            {
                var hrCrp = crpList.GetCostRatePeriodForDate(CostRatePeriodType.HourlyRate, accountingPeriodStart.Value);
                if (hrCrp != null && hrCrp.CostRateValue.HasValue)
                {
                    hourlyRate = hrCrp.CostRateValue.Value;
                }
            }

            invoiceItem.ItemPeriodStart = accountingPeriodStart;
            invoiceItem.ItemPeriodEnd = accountingPeriodEnd;
            invoiceItem.AmountPerUnit = hourlyRate;

            if (hasAbsenceTime)
            {
                invoiceItem.UnitCount = 0;
            }
            else
            {
                invoiceItem.UnitCount = scap.ApprovedBEPerInterval;
                if (scap.ApprovedBEInterval.HasValue && scap.ApprovedBEInterval.Value == SupportConceptApprovalInterval.Yearly)
                {
                    if (invoiceItem.UnitCount.HasValue && invoiceItem.UnitCount.Value == 343)
                    {
                        invoiceItem.UnitCount = 28.6m;
                    }
                    else
                        invoiceItem.UnitCount /= 12;
                }
            }

            invoiceItem.AmountTotal = Math.Round(hourlyRate * Math.Round(invoiceItem.UnitCount.Value, 2, MidpointRounding.AwayFromZero), 2, MidpointRounding.AwayFromZero);
            invoiceItem.GrossAmountTotal = invoiceItem.AmountTotal;
            invoiceItem.SupportConceptApprovalPeriodOid = scap.Oid;

            itemList.Add(invoiceItem);


            return itemList;
        }

        private bool HasAbsenceTimeInMonth(IList<AbsenceTime> absenceTimes, DateTime dateTime)
        {
            var start = new DateTime(dateTime.Year, dateTime.Month, 1);

            foreach (var at in absenceTimes)
            {
                if (at.Start.HasValue && at.Start < start.AddMonths(1))
                {
                    if (!at.End.HasValue || at.End.Value >= start)
                    {
                        return true;
                    }
                }
            }
            return false;
        }

        public override InvoiceItem CreateInvoiceItem(ServiceRecordDC iServiceRecord, SupportConceptApprovalPeriod scap, Calculations calc)
        {
            var invoiceItem = new InvoiceItem();

            var bd = calc.GetBillingData(iServiceRecord);

            invoiceItem.AmountPerUnit = bd.AmountPerUnit ?? 0;
            invoiceItem.UnitCount = bd.UnitCount ?? 0;
            invoiceItem.AmountTotal = bd.AmountTotal ?? 0;
            invoiceItem.ItemPeriodStart = bd.BillingPeriodStart;
            invoiceItem.ItemPeriodEnd = bd.BillingPeriodEnd;
            invoiceItem.RateFactor = bd.RateFactor ?? 0;
            invoiceItem.GrossAmountTotal = bd.GrossAmountTotal;
            invoiceItem.AccountingInterval = bd.AccountingInterval;

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

            return invoiceItem;
        }

        public virtual 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)
                {
                    if (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;
                        }
                    }
                }
            }
        }
    }
}
