using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VetClinicBusinessLogic.OfficePackage;
using VetClinicBusinessLogic.OfficePackage.HelperModels;
using VetClinicContracts.BindingModels;
using VetClinicContracts.BusinessLogicsContracts;
using VetClinicContracts.SearchModels;
using VetClinicContracts.StoragesContracts;
using VetClinicContracts.ViewModels;
using VetClinicDataBaseImplement.Implements;

namespace VetClinicBusinessLogic.BusinessLogics
{
	public class ReportLogicPharmacist : IReportLogicPharmacist
	{
		private readonly IServiceStorage _serviceStorage;
		private readonly IMedicineStorage _medicineStorage;
		private readonly AbstractSaveToExcelPharmacist _saveToExcel;
		private readonly AbstractSaveToWordPharmacist _saveToWord;
		private readonly AbstractSaveToPdfPharmacist _saveToPdf;
		public ReportLogicPharmacist(IServiceStorage serviceStorage, IMedicineStorage medicineStorage,
			AbstractSaveToExcelPharmacist saveToExcel, AbstractSaveToWordPharmacist saveToWord,
			AbstractSaveToPdfPharmacist saveToPdf)
		{
			_serviceStorage = serviceStorage;
			_medicineStorage = medicineStorage;
			_saveToExcel = saveToExcel;
			_saveToWord = saveToWord;
			_saveToPdf = saveToPdf;
		}

		public List<ListAnimalsViewModel> GetServiceAnimals(List<int> services)
		{

			List<ListAnimalsViewModel> ans = new();
			List<Tuple<ServiceViewModel, List<Tuple<MedicineViewModel, List<AnimalViewModel>>>>> response = 
				_serviceStorage.GetReportInfo(new ListAnimalsSearchModel { servicesIds = services});

			foreach (var service in response)
			{
				Dictionary<int, (AnimalViewModel, int)> counter = new();
				foreach (var medicine in service.Item2)
				{
					foreach (var animal in medicine.Item2)
					{
						if (!counter.ContainsKey(animal.Id))
							counter.Add(animal.Id, (animal, 1));
						else
						{
							counter[animal.Id] = (counter[animal.Id].Item1, counter[animal.Id].Item2 + 1);
						}
					}
				}
				List<AnimalViewModel> res = new();
				foreach (var cnt in counter)
				{
					if (cnt.Value.Item2 != service.Item2.Count)
						continue;
					res.Add(cnt.Value.Item1);
				}
				ans.Add(new ListAnimalsViewModel
				{
					ServiceName = service.Item1.ServiceName,
					Animals = res
				});
			}
			return ans;
		}

		public void SaveAnimalsToExcelFile(ListAnimalsBindingModel model)
		{
			_saveToExcel.CreateReport(new ExcelInfoPharmacist
			{
				FileName = model.FileName,
				Title = "Список животных для услуг",
				ServicesAnimals = GetServiceAnimals(model.Services)
			});
		}

		public void SaveAnimalsToWordFile(ListAnimalsBindingModel model)
		{
			_saveToWord.CreateDoc(new WordInfoPharmacist
			{
				FileName = model.FileName,
				Title = "Список животных для услуг",
				ServicesAnimals = GetServiceAnimals(model.Services)
			});
		}

		public List<VisitsGuidesViewModel> GetMedicineVisitsAndGuidances(VisitsGuidesBindingModel model)
		{
			List<VisitsGuidesViewModel> ans = new();
			List<Tuple<MedicineViewModel, List<Tuple<ServiceViewModel, List<GuidanceViewModel>>>>> responseGuides =
				_medicineStorage.GetGuidancesInfo(new VisitGuidesSearchModel { DateFrom = model.DateFrom!,  DateTo = model.DateTo!, PharmacistId = model.PharmacistId!});
			List<Tuple<MedicineViewModel, List<Tuple<ServiceViewModel, List<VisitViewModel>>>>> responseVisits =
				_medicineStorage.GetVisitsInfo(new VisitGuidesSearchModel { DateFrom = model.DateFrom!, DateTo = model.DateTo!, PharmacistId = model.PharmacistId! });
			Dictionary<int, VisitsGuidesViewModel> dict = new();

			foreach(var medicine in responseGuides)
			{
				dict.Add(medicine.Item1.Id, new());
				dict[medicine.Item1.Id].MedicineName = medicine.Item1.MedicineName;
				foreach(var service in medicine.Item2)
				{
					foreach(var guidance in service.Item2)
					{
						dict[medicine.Item1.Id].Guidances.Add(guidance);
					}
				}
			}

			foreach (var medicine in responseVisits)
			{
				HashSet<int> used = new();
				foreach (var service in medicine.Item2)
				{
					foreach (var visit in service.Item2)
					{
						if (used.Contains(visit.Id))
							continue;
						dict[medicine.Item1.Id].Visits.Add(visit);
					}
				}
				ans.Add(dict[medicine.Item1.Id]);
			}
			return ans;
		}

		public void SaveMedicinesToPdfFile(VisitsGuidesBindingModel model)
		{
			_saveToPdf.CreateDoc(new PdfInfo
			{
				FileName = model.FileName,
				Title = "Список медикаментов",
				DateFrom = model.DateFrom!,
				DateTo = model.DateTo!,
				Medicines = GetMedicineVisitsAndGuidances(model)
			});

		}
	}
}
