using BankContracts.BindingModels;
using BankContracts.BusinessLogicsContracts;
using BankContracts.StoragesContracts;
using BankContracts.ViewModels;
using BankContracts.SearchModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using BankBusinessLogic.OfficePackage;
using BankBusinessLogic.OfficePackage.HelperModels;

namespace BankBusinessLogic.BusinessLogics
{
	public class ReportLogic : IReportLogic
	{
		private readonly ITransferStorage _transferStorage;
		private readonly IPaymentStorage _paymentStorage;
		private readonly ICurrencyPurchaseStorage _currencyPurchaseStorage;
		private readonly ICurrencyStorage _currencyStorage;

        private readonly AbstractSaveToWord _saveToWord;
        private readonly AbstractSaveToExcel _saveToExcel;
        private readonly AbstractSaveToPdf _saveToPdf;

		public ReportLogic(ITransferStorage transferStorage, IPaymentStorage paymentStorage, ICurrencyStorage currencyStorage, ICurrencyPurchaseStorage currencyPurchaseStorage, AbstractSaveToWord saveToWord, AbstractSaveToExcel saveToExcel, AbstractSaveToPdf saveToPdf)
		{
			_transferStorage = transferStorage;
			_paymentStorage = paymentStorage;
            _currencyStorage = currencyStorage;
			_currencyPurchaseStorage = currencyPurchaseStorage;
            _saveToWord = saveToWord;
            _saveToExcel = saveToExcel;
            _saveToPdf = saveToPdf;
		}

		public List<ReportPaymentCurrencyPurchaseViewModel> GetPaymentPurchase(List<PaymentBindingModel> payments)
		{
			var list = new List<ReportPaymentCurrencyPurchaseViewModel>();
			var currencies = _currencyStorage.GetFullList();
			var currencyPurchases = _currencyPurchaseStorage.GetFullList();

			foreach(var payment in payments)
			{
				var record = new ReportPaymentCurrencyPurchaseViewModel
				{
					PaymentId = payment.Id,
					PaymentDate = payment.PaymentDate,
					Purchases = new List<(int, float)>()
				};
				var foundCurrenciesId = new List<int>();
				//находим валюты, привязанные к платежу
				foreach (var currency in currencies)
				{
                    if (payment.CurrencyPayments.ContainsKey(currency.Id)) foundCurrenciesId.Add(currency.Id);
                }
				//выбираем из всех закупок те, которые относятся к найденным валютам
                foreach (var currencyPurchase in currencyPurchases)
                {
					foreach(var currencyId in foundCurrenciesId)
					{
                        if (currencyPurchase.CurrencyId == currencyId)
                        {
                            record.Purchases.Add(new(currencyPurchase.Id, currencyPurchase.Amount));
							break;
                        }
                    }
                }
                list.Add(record);
			}

			return list;
		}

		public List<ReportTransferCurrencyPurchaseViewModel> GetTransferPurchase(ReportBindingModel model)
		{
			var transfers = _transferStorage.GetFilteredList(new TransferSearchModel { DateFrom = model.DateFrom, DateTo = model.DateTo });
			var currencies = _currencyStorage.GetFullList();
            var currencyPurchases = _currencyPurchaseStorage.GetFullList();
            var list = new List<ReportTransferCurrencyPurchaseViewModel>();

			foreach (var transfer in transfers)
			{
                var record = new ReportTransferCurrencyPurchaseViewModel
                {
                    TransferId = transfer.Id,
                    TransferDate = transfer.TransferDateTime,
                    Purchases = new List<CurrencyPurchaseViewModel>()
                };
				var payment = _paymentStorage.GetElement(new PaymentSearchModel { Id = transfer.PaymentId});
				if (payment == null)
				{
					throw new InvalidOperationException("Платеж не был найден!");
				}
				var foundCurrenciesId = new List<int>();
                //находим валюты, привязанные к платежу
                foreach (var currency in currencies)
                {
                    if (payment.CurrencyPayments.ContainsKey(currency.Id)) foundCurrenciesId.Add(currency.Id);
                }
                //выбираем из всех закупок те, которые относятся к найденным валютам
                foreach (var currencyPurchase in currencyPurchases)
                {
                    foreach (var currencyId in foundCurrenciesId)
                    {
                        if (currencyPurchase.CurrencyId == currencyId)
                        {
                            record.Purchases.Add(currencyPurchase);
                            break;
                        }
                    }
                }
                list.Add(record);
            }
			
            return list;
        }

        public List<ReportCurrencyTransferViewModel> GetCurrencyTransfers(List<CurrencyBindingModel> currencies)
        {
            var list = new List<ReportCurrencyTransferViewModel>();
            var payments = _paymentStorage.GetFullList();
            var transfers = _transferStorage.GetFullList();
            foreach(var currency in currencies)
            {
                var record = new ReportCurrencyTransferViewModel
                {
                    CurrencyId = currency.Id,
                    CurrencyName = currency.Name,
                    Transfers = new List<TransferViewModel>(),
                };
                var paymentsId = new List<int>();
                foreach(var payment in payments)
                {
                    if (payment.CurrencyPayments.ContainsKey(currency.Id)) paymentsId.Add(payment.Id);
                }
                foreach(var transfer in transfers)
                {
                    foreach(int paymentId in paymentsId)
                    {
                        if (paymentId == transfer.PaymentId)
                        {
                            record.Transfers.Add(transfer);
                        }
                    }
                }
                list.Add(record);
            }
            return list;
        }
        public List<ReportCurrencyPurchasePaymentViewModel> GetPurchasePayment(ReportBindingModel model)
        {
            var purchases = _currencyPurchaseStorage.GetFilteredList(new CurrencyPurchaseSearchModel { DateFrom = model.DateFrom, DateTo = model.DateTo });
            var list = new List<ReportCurrencyPurchasePaymentViewModel>();
            var payments = _paymentStorage.GetFullList();
            foreach (var purchase in purchases)
            {
                var record = new ReportCurrencyPurchasePaymentViewModel
                {
                    CurrencyPurchaseId = purchase.Id,
                    PurchaseDate = purchase.PurchaseDate,
                    CurrencyName = purchase.CurrencyName,
                    Payments = new List<(int PaymentId, DateTime PaymentDate)>(),
                };
                var paymentsId = new List<int>();
                foreach (var payment in payments)
                {
                    if (payment.CurrencyPayments.ContainsKey(purchase.CurrencyId)) record.Payments.Add(new(payment.Id, payment.PaymentDate));
                }
                list.Add(record);
            }
            return list;
        }

        public MemoryStream SavePaymentPurchaseToExcel(ReportBindingModel model, List<PaymentBindingModel> payments)
		{
			var result = GetPaymentPurchase(payments);
            return _saveToExcel.CreateOperatorReport(new ExcelInfo
            {
                Title = "Отчёт о выплатах",
                FileName = model.FileName,
                Payments = result
            });
        }

		public MemoryStream SavePaymentPurchaseToWord(ReportBindingModel model, List<PaymentBindingModel> payments)
		{
			var result = GetPaymentPurchase(payments);
            return _saveToWord.CreateOperatorDoc(new WordInfo
            {
                Title = "Отчёт о выплатах",
                FileName = model.FileName,
                Payments = result
            });
		}

		public MemoryStream SaveTransferPurchaseToPDF(ReportBindingModel model)
		{
            if (!model.DateFrom.HasValue || !model.DateTo.HasValue)
            {
                throw new InvalidOperationException("Отсутствуют даты для отчёта!");
            }
			var result = GetTransferPurchase(model);
            return _saveToPdf.CreateOperatorDoc(new PdfInfo
            {
                Title = "Отчёт о зачислениях",
                DateFrom = model.DateFrom.Value,
                DateTo = model.DateTo.Value,
                Transfers = result
            });
		}

        public MemoryStream SaveCurrencyTransfersToExcel(ReportBindingModel model,
            List<CurrencyBindingModel> currencies)
        {
            var report = GetCurrencyTransfers(currencies);
            return _saveToExcel.CreateBankOperatorReport(new ExcelInfo
            {
                Title = "Отчёт по валютам",
                FileName = model.FileName,
                Currencies = report
            });
        }

        public MemoryStream SaveCurrencyTransfersToWord(ReportBindingModel model, List<CurrencyBindingModel> currencies)
        {
            var report = GetCurrencyTransfers(currencies);
            return _saveToWord.CreateBankOperatorDoc(new WordInfo
            {
                Title = "Отчёт по валютам",
                FileName = model.FileName,
                Currencies = report
            });
        }
        public MemoryStream SavePurchasePaymentToPDF(ReportBindingModel model)
        {
            if (!model.DateFrom.HasValue || !model.DateTo.HasValue)
            {
                throw new InvalidOperationException("Отсутствуют даты для отчёта!");
            }
            var report = GetPurchasePayment(model);
            return _saveToPdf.CreateBankOperatorDoc(new PdfInfo
            {
                Title = "Отчёт по закупкам",
                DateFrom = model.DateFrom.Value,
                DateTo = model.DateTo.Value,
                CurrencyPurchases = report
            });

        }
    }
}
