using CaseAccountingBusinessLogic.BusinessLogic.OfficePackage;
using CaseAccountingBusinessLogic.OfficePackage;
using CaseAccountingContracts.BindingModels;
using CaseAccountingContracts.BusinessLogicContracts;
using CaseAccountingContracts.SearchModels;
using CaseAccountingContracts.StoragesContracts;
using CaseAccountingContracts.ViewModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace CaseAccountingBusinessLogic.BusinessLogics
{
    public class ReportProviderLogic : IReportProviderLogic
    {
        private readonly ICaseStorage _caseStorage;
        private readonly ISpecializationStorage _specializationStorage;
        private readonly IHearingStorage _hearingStorage;
        private readonly ILawyerStorage _lawyerStorage;
        private readonly WordBuilderProvider _wordBuilder;
        private readonly ExcelBuilderProvider _excelBuilder;
        private readonly PdfBuilderProvider _pdfBuilder;
        private readonly MailSender _mailSender;

        public ReportProviderLogic(ICaseStorage caseStorage, ISpecializationStorage specializationStorage, IHearingStorage hearingStorage, 
            ILawyerStorage lawyerStorage, WordBuilderProvider wordBuilder, ExcelBuilderProvider excelBuilder,
            PdfBuilderProvider pdfBuilder, MailSender mailSender)
        {
            _caseStorage = caseStorage ?? throw new ArgumentNullException(nameof(caseStorage));
            _specializationStorage = specializationStorage ?? throw new ArgumentNullException(nameof(specializationStorage));
            _hearingStorage = hearingStorage ?? throw new ArgumentNullException(nameof(hearingStorage));
            _lawyerStorage = lawyerStorage ?? throw new ArgumentNullException(nameof(lawyerStorage));
            _wordBuilder = wordBuilder ?? throw new ArgumentNullException(nameof(wordBuilder));
            _excelBuilder = excelBuilder ?? throw new ArgumentNullException(nameof(excelBuilder));
            _pdfBuilder = pdfBuilder ?? throw new ArgumentNullException(nameof(pdfBuilder));
            _mailSender = mailSender ?? throw new ArgumentNullException(nameof(mailSender));
        }

        public List<ReportCaseSpecializationViewModel> GetCaseSpecialization(List<CaseViewModel> models)
        {
            List<ReportCaseSpecializationViewModel> list = new();
            foreach (var model in models)
            {
                var specialization = _specializationStorage.GetElement(new SpecializationSearchModel { Id = model.SpecializationId });
                var caseModel = _caseStorage.GetElement(new CaseSearchModel { Id = model.Id });
                if (specialization == null)
                {
                    throw new Exception("Некоректные данные по специализации");
                }
                if (caseModel == null)
                {
                    throw new Exception("Некоректные данные по делу");
                }

                bool hasSpec = false;
                if (list.Count > 0)
                {
                    foreach (var report in list)
                    {
                        if (hasSpec = report.Specialization.Equals(specialization.Name))
                        {
                            report.Cases.Add("Дело #" + caseModel.Id.ToString());
                            break;
                        }
                    }
                }
                if (!hasSpec)
                {
                    var newElement = new ReportCaseSpecializationViewModel
                    {
                        Specialization = specialization.Name,
                        Cases = new()
                    };
                    newElement.Cases.Add("Дело #" + caseModel.Id.ToString());
                    list.Add(newElement);
                }
            }
            return list;
        }

        public List<ReportHearingLawyerViewModel> GetHearingLawyer(ReportBindingModel model)
        {
            var hearings = _hearingStorage
                .GetFilteredList(new HearingSearchModel { UserId = model.UserId })
                .Where(x => model.DateFrom <= x.Date && model.DateTo >= x.Date);
            var list = new List<ReportHearingLawyerViewModel>();
            foreach (var hearing in hearings)
            {
                var record = new ReportHearingLawyerViewModel
                {
                    Hearing = "Номер слушания #" + hearing.Id.ToString(),
                    CaseLawyers = new()
                };
                var caseId = _caseStorage.GetElement(new CaseSearchModel { Id = hearing.CaseId }).Id;
                foreach (var lawyer in _lawyerStorage.GetLawyerMTM(caseId))
                {
                    record.CaseLawyers.Add(new CaseLawyerViewModel
                    {
                        Case = "Дело #" + caseId.ToString(),
                        Date = hearing.Date,
                        Lawyer = lawyer.Surname + " " + lawyer.Name + " " + lawyer.Patronymic
                    });
                }
                list.Add(record);
            }
            return list;
        }

        public byte[] SaveListFile(CaseSpecializationListBindingModel model)
        {
            byte[] file = Array.Empty<byte>();

            string title = "Список специализаций по выбраным делам";

            if (model.FileType == "docx")
            {
                _wordBuilder.CreateDocument();
                _wordBuilder.CreateTitle(title);
                _wordBuilder.CreateCaseSpecializationTable(GetCaseSpecialization(model.Cases));
                file = _wordBuilder.GetFile();
            }
            else if (model.FileType == "xlsx")
            {
                _excelBuilder.CreateDocument();
                _excelBuilder.CreateTitle(title);
                _excelBuilder.CreateCaseSpecializationTable(GetCaseSpecialization(model.Cases));
                file = _excelBuilder.GetFile();
            }
            return file;
        }

        public void SendByMailStatusReport(ReportBindingModel reportModel)
        {
            byte[] file = _pdfBuilder.GetHearingLawyerReportFile(new()
            {
                Title = "Отчет по слушаниям",
                DateFrom = reportModel.DateFrom,
                DateTo = reportModel.DateTo,
                Records = GetHearingLawyer(reportModel)
            });
            _mailSender.SendMailAsync(new()
            {
                MailAddress = reportModel.UserEmail,
                Subject = "Отчет по слушаниям",
                Text = $"За период с {reportModel.DateFrom.ToShortDateString()} " +
                    $"по {reportModel.DateTo.ToShortDateString()}.",
                File = file
            });
        }
    }
}
