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 ReportLogicAdmin : IReportLogicAdmin
	{
		private readonly IAnimalStorage _animalStorage;
		private readonly IVisitStorage _visitStorage;
		private readonly AbstractSaveToExcelAdmin _saveToExcel;
		private readonly AbstractSaveToWordAdmin _saveToWord;
		private readonly AbstractSaveToPdfAdmin _saveToPdf;
		public ReportLogicAdmin(IAnimalStorage animalStorage, IVisitStorage visitStorage,
			AbstractSaveToExcelAdmin saveToExcel, AbstractSaveToWordAdmin saveToWord,
			AbstractSaveToPdfAdmin saveToPdf)
		{
			_animalStorage = animalStorage;
			_visitStorage = visitStorage;
			_saveToExcel = saveToExcel;
			_saveToWord = saveToWord;
			_saveToPdf = saveToPdf;
		}

		public List<ListServicesViewModel> GetAnimalServices(List<int> animals)
		{

			List<ListServicesViewModel> ans = new();
			List<Tuple<AnimalViewModel, List<Tuple<MedicineViewModel, List<ServiceViewModel>>>>> response =
				_animalStorage.GetReportInfo(new ListServicesSearchModel { animalsIds = animals});

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

		public void SaveServicesToExcelFile(ListServicesBindingModel model)
		{
			_saveToExcel.CreateReport(new ExcelInfoAdmin
			{
				FileName = model.FileName,
				Title = "Список услуг для животных",
				AnimalsServices = GetAnimalServices(model.Animals)
			});
		}

		public void SaveServicesToWordFile(ListServicesBindingModel model)
		{
			_saveToWord.CreateDoc(new WordInfoAdmin
			{
				FileName = model.FileName,
				Title = "Список услуг для животных",
				AnimalsServices = GetAnimalServices(model.Animals)
			});
		}

		public List<MedicinesVaccinationsViewModel> GetVisitMedicinesAndVaccinations(MedicinesVaccinationsBindingModel model)
		{
			List<MedicinesVaccinationsViewModel> ans = new();
			List<Tuple<VisitViewModel, List<Tuple<AnimalViewModel, List<VaccinationViewModel>>>>> responseVaccinations =
				_visitStorage.GetVaccinationsInfo(new MedicineVaccinationsSearchModel { DateFrom = model.DateFrom!,  DateTo = model.DateTo!, AdminId = model.AdminId!});
			List<Tuple<VisitViewModel, List<Tuple<AnimalViewModel, List<MedicineViewModel>>>>> responseMedicines =
				_visitStorage.GetMedicinesInfo(new MedicineVaccinationsSearchModel { AdminId = model.AdminId! });
			Dictionary<int, MedicinesVaccinationsViewModel> dict = new();

			foreach(var visit in responseVaccinations)
			{
				if (visit.Item1.DateVisit >= model.DateFrom && visit.Item1.DateVisit <= model.DateTo)
				{


					dict.Add(visit.Item1.Id, new());
					dict[visit.Item1.Id].VisitName = visit.Item1.NameVisit;
					dict[visit.Item1.Id].DateVisit = visit.Item1.DateVisit;
					foreach (var animal in visit.Item2)
					{
						foreach (var vaccination in animal.Item2)
						{
							dict[visit.Item1.Id].Vaccinations.Add(vaccination);
						}
					}
				}
			}

			foreach (var visit in responseMedicines)
			{
				if (visit.Item1.DateVisit >= model.DateFrom && visit.Item1.DateVisit <= model.DateTo)
				{
					if (!dict.ContainsKey(visit.Item1.Id))
					{
						dict.Add(visit.Item1.Id, new MedicinesVaccinationsViewModel());
						dict[visit.Item1.Id].VisitName = visit.Item1.NameVisit;
						dict[visit.Item1.Id].DateVisit = visit.Item1.DateVisit;
					}
					HashSet<int> used = new();
					foreach (var animal in visit.Item2)
					{
						foreach (var medicine in animal.Item2)
						{
							if (used.Contains(medicine.Id))
								continue;
							
								dict[visit.Item1.Id].Medicines.Add(medicine);
							
							used.Add(medicine.Id);
						}
					}
				}
				
				
			}
			foreach (var kvp in dict)
			{
				ans.Add(kvp.Value);
			}
			return ans;
		}

		public void SaveVisitsToPdfFile(MedicinesVaccinationsBindingModel model)
		{
			_saveToPdf.CreateDoc(new PdfInfo
			{
				FileName = model.FileName,
				Title = "Список визитов",
				DateFrom = model.DateFrom!,
				DateTo = model.DateTo!,
				Visits = GetVisitMedicinesAndVaccinations(model)
			});

		}
	}
}
