using System;
using System.Activities;
using System.Collections.Generic;
using System.Linq;
using AutoDictionaryClient.Code.KaskoClient.Interfaces;
using iRIS.Framework.Common;
using iRIS.Framework.Cqrs.Interfaces;
using iRIS.Framework.Data;
using iRIS.Framework.Entity.Dictionary.DictionaryVersionProcessor;
using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.Framework.Entity.Dictionary.LocalDictionaryCache;
using iRIS.Framework.Entity.Metadata;
using iRIS.Framework.Entity.Metadata.Manager.Interfaces;
using iRIS.Framework.FileManagement;
using iRIS.Framework.Platform.Entities;
using iRIS.Framework.Security.Entities;
using iRIS.Framework.Validation;
using iRIS.Framework.Workflow.Activities;
using iRIS.Framework.Workflow.Data;
using iRIS.InsuranceCore.Code.Helpers;
using iRIS.InsuranceCore.Code.Queries;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.Custom;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.InsuranceCore.Entities.Enums;
using iRIS.InsuranceCore.Infrastructure.Helpers;
using iRIS.InsuranceCore.OSS.Code.Dto.Uni;
using iRIS.KaskoCore.Code.Extensions;
using iRIS.KaskoCore.Code.Helpers;
using iRIS.KaskoCore.Printing.Code;
using iRIS.KaskoLink2.Code.CreateOn.DealInitialization;
using iRIS.KaskoLink2.Code.Subscription.Implementations;
using iRIS.KaskoLink2.Code.TypeExtensions;
using iRIS.KaskoLink2.Implementations.Code.Implementations.AutoDictionary.Interfaces;
using iRIS.KaskoLink2.Modification.Code.Constants;
using iRIS.KaskoLink2.Modification.Code.CustomProcesses;
using iRIS.KaskoLink2.Modification.Code.Implementations.ChangeValidations;
using iRIS.KaskoLink2.Modification.Code.Models;
using iRIS.KaskoLink2.Modification.Code.Models.Validators;
using iRIS.Printing.Code.Activities;
using iRIS.Printing.Code.Helpers;
using iRIS.Printing.Code.Interfaces;
using iRIS.Printing.Code.Queries;
using Microsoft.Extensions.DependencyInjection;

namespace iRIS.KaskoLink2.Modification.Code.Procedures
{
    public class KaskoModificationProcedures : ActivityProcedures
    {
        public KaskoModificationProcedures(ActivityContext activityContext)
            : base(activityContext)
        {
        }

        public void InitializeDeals(Basket basket, List<string> productDictCodes)
        {
            var mediator = ServiceProvider.GetRequiredService<ICqrsMediator>();
            var metadataManager = ServiceProvider.GetRequiredService<IMetadataManager>();
            var dictionariesVersion = ServiceProvider.GetRequiredService<IDictionariesVersionControl>();

            foreach (var productDictCode in productDictCodes)
            {
                var product = mediator.ResolveQuery<IQueryProduct>().GetByProductDictCode(productDictCode);

                var dealInitializer = KaskoDealInitializerFactory.GetInitializerFor(null, basket, product, metadataManager);
                var deal = dealInitializer.InitializeDeal();
                dictionariesVersion.SetVersions(new List<BaseEntity>() { deal }, DT.Now);

                deal.IsInBasket = true;
                deal.IsVI = true;

                basket.Deals.Add(deal);
            }
        }

        public void UpdateBasket(Basket basket, KaskoModificationBasketModel update)
        {
            if (!basket.EntityContext.ContainsKey(nameof(KaskoModificationBasketModel)))
            {
                basket.EntityContext.Add(nameof(KaskoModificationBasketModel), update);
            }

            var deal = basket.GetKaskoDeal();
            if (deal != null)
            {
                if (update.Deal == null)
                {
                    return;
                }

                var updateDeal = update.Deal;
                var updateOwner = updateDeal.Owner?.Person;
                var updateInsurant = updateDeal.Insurant?.Person;
                var updateAuto = updateDeal.Auto;
                var updateTsIdentityCard = updateDeal.Auto?.TsIdentityCard;
                var updateDrivers = updateDeal.Drivers;

                deal.AutoDeal.IsMultidrive = updateDeal.IsMultidrive ?? deal.AutoDeal.IsMultidrive;
                deal.ChangesStartDate = updateDeal.ChangeDate;
                deal.AutoDeal.DriverMinAge = updateDeal.MinimalAge ?? deal.AutoDeal.DriverMinAge;
                deal.AutoDeal.DriverMinExperience = updateDeal.MinimalDrivingExperience ?? deal.AutoDeal.DriverMinExperience;

                var insurant = deal.Insurant;
                var owner = deal.GetOwner();
                var drivers = deal.AutoDeal.Drivers;
                var auto = deal.GetAuto();
                var tsIdentityCard = deal.AutoDeal?.TsIdentityCard;

                UpdateDealDateStart(updateDeal, deal);
                UpdateOwner(updateOwner, owner);
                UpdateInsurant(updateInsurant, insurant);
                UpdateDrivers(updateDrivers, drivers);
                UpdateAuto(updateAuto, auto);
                UpdateTsIdentityCard(updateTsIdentityCard, tsIdentityCard);
                UpdateSuggestedBank(updateDeal.Auto, deal);

                var autoDictionaryBasketUpdater = ServiceProvider.GetRequiredService<IAutoDictionaryBasketUpdater>();
                autoDictionaryBasketUpdater.UpdateAutoDictionaryValues(basket);
            }
        }

        private void UpdateDealDateStart(KaskoModificationDealModel updateDeal, Deal deal)
        {
            if (updateDeal.DateStart == DateTime.MinValue || updateDeal.DateEnd == DateTime.MinValue)
            {
                return;
            }

            deal.EntityContext.TryGetValue("ossPolicyStatus", out var ossPolicyStatus);

            if (ossPolicyStatus == SubscriptionConstants.OssCheckPolicyActualityValid)
            {
                AddCustomError("Недопустимые изменения: невозможно изменение сроков действия договора. Полис находится в статусе \"Действует\"", ModificationErrorCodes.UnacceptableChanges);
                return;
            }

            if (updateDeal?.DateStart < deal?.DateStart || updateDeal?.DateStart > deal.DateStart?.AddMonths(1).AddDays(1))
            {
                AddCustomError("Недопустимые изменения: невозможно изменение сроков действия договора более, чем на 1 месяц", ModificationErrorCodes.UnacceptableChanges);
                return;
            }

            deal.DateStart = updateDeal?.DateStart;
            deal.DateEnd = updateDeal?.DateEnd ?? deal.DateStart?.AddYears(1).AddDays(-1);
        }

        private void UpdateSuggestedBank(KaskoModificationAutoModel auto, Deal deal)
        {
            var queryBank = ServiceProvider.GetRequiredService<IQueryBank>();
            var dealAuto = deal.InsuranceObjects[0].Auto;

            var bank = queryBank.GetBankByBIK(auto.BankOfCreditBik) ?? queryBank.GetBankByName(auto.BankOfCredit);
            if (bank == null)
            {
                AddCustomError("Ошибка валидации: название банка или БИК не соответствует справочнику", ModificationErrorCodes.UnacceptableChanges);
                return;
            }

            if (auto.InCredit == null)
            {
                return;
            }

            if (auto.InCredit == true && dealAuto.IsCreditAuto == false)
            {
                var suggestedBank = new SuggestedBank
                {
                    Name = bank.Subject.LegalEntity.Name,
                    ShortName = bank.Subject.LegalEntity.ShortName,
                    BIK = bank.BIK,
                    Bank_Id = bank.Id > 0 ? bank.Id : null
                };

                deal.SetBank(suggestedBank);
                dealAuto.IsCreditAuto = true;
            }
            else if (auto.InCredit == false && dealAuto.IsCreditAuto == true)
            {
                dealAuto.IsCreditAuto = false;
                deal.SetBank(null);
            }
        }

        public void CapitalizeNames(Basket basket)
        {
            var deal = basket.GetKaskoDeal();

            if (deal != null)
            {
                var insurant = deal.GetInsurantPerson();
                var owner = deal.GetOwner()?.GetOwnerPerson();

                CapitalizePersonNames(insurant);
                CapitalizePersonNames(owner);

                deal.AutoDeal.Drivers.ForEach(d => CapitalizePersonNames(d.GetPerson()));
            }
        }

        public void ValidateRequestModel(KaskoModificationBasketModel model)
        {
            var modificationValidator = ServiceProvider.GetRequiredService<KaskoModificationBasketModelValidator>();
            var validationAggregator = ServiceProvider.GetRequiredService<IValidationResultsAggregator>();
            var autoDictionaryClient = ServiceProvider.GetRequiredService<IKaskoAutoDictionaryClientV1>();

            var result = modificationValidator.Validate(model);
            var auto = model.Deal.Auto;
            var transmissionTypes = autoDictionaryClient.GetAutoTransmissionTypes();
            var engineTypes = autoDictionaryClient.GetAutoEngineTypes();

            if (auto?.TransmissionTypeCode != null &&
                    !transmissionTypes.Any(t => t.Code == auto.TransmissionTypeCode))
            {
                AddCustomError("Допускается передача только кода по справочнику для transmissionTypeCode", ModificationErrorCodes.UnacceptableChanges);
            }

            if (auto?.EngineTypeCode != null &&
                    !engineTypes.Any(e => e.Code == auto.EngineTypeCode))
            {
                AddCustomError("Допускается передача только кода по справочнику для engineTypeCode", ModificationErrorCodes.UnacceptableChanges);
            }

            if (!result.IsValid)
            {
                foreach (var item in result.Errors)
                {
                    string formattedErrorMessage = item.PropertyName == "Deal.ChangeDate"
                        ? $"Код: {ModificationErrorCodes.IncorrectStartDate}. {item.ErrorMessage}."
                        : $"Код: {ModificationErrorCodes.UnacceptableChanges}. Недопустимые изменения: {item.ErrorMessage}.";

                    validationAggregator.AppendValidationErrors(new ValidationError
                    {
                        CriticalLevel = ValidationCriticalLevel.CantContProc,
                        ErrorMessage = formattedErrorMessage
                    });
                }
            }
        }

        public void CheckChanges(Basket basket, KaskoModificationBasketModel modification, ModificationChangesResult changesResult)
        {
            var changes = changesResult.Changes.ChangesDictionary;
            var deal = basket.GetKaskoDeal();

            var isInsurantGettingMarried = modification.Deal?.Insurant?.Person?.IsGettingMarried;
            var isOwnerGettingMerried = modification.Deal?.Owner?.Person?.IsGettingMarried;
            var isDriverGettingMerried = modification.Deal?.Drivers?.Any(d => d.IsGettingMarried == true);

            var validator = new KaskoModificationChangesLink2Validator(changes);

            var error = validator.CheckAutoDeal()
                .MergeWith(validator.CheckDrivers(isDriverGettingMerried))
                .MergeWith(validator.CheckAuto())
                .MergeWith(validator.CheckInsurant(isInsurantGettingMarried))
                .MergeWith(validator.CheckOwner(isOwnerGettingMerried));

            var validationAggregator = ServiceProvider.GetRequiredService<IValidationResultsAggregator>();

            // Проверка даты начала действия ДС
            if (modification.Deal.ChangeDate > deal.DateEnd?.AddDays(-1))
            {
                string errorMessage = $"Код: {ModificationErrorCodes.IncorrectStartDate}. Дата начала ДС не может быть раньше текущей даты + 1 день и позже даты окончания действия полиса - 1 день. Переданная в запросе дата начала действия ДС {modification.Deal.ChangeDate.ToShortDateString()} не попадает в указанный промежуток.";
                validationAggregator.AppendValidationErrors(new ValidationError
                {
                    CriticalLevel = ValidationCriticalLevel.CantContProc,
                    ErrorMessage = errorMessage
                });
            }

            foreach (string errorMessage in error.Errors)
            {
                string formattedErrorMessage = $"Код: {ModificationErrorCodes.UnacceptableChanges}. Недопустимые изменения: {errorMessage}";
                validationAggregator.AppendValidationErrors(new ValidationError
                {
                    CriticalLevel = ValidationCriticalLevel.CantContProc,
                    ErrorMessage = formattedErrorMessage
                });
            }
        }

        public void SavePrintingStore(Basket basket)
        {
            var printStoreManager = ServiceProvider.GetRequiredService<IPrintingStoreManager>();
            var settingsManager = ServiceProvider.GetRequiredService<IEntitySettingsManager>();
            var mediator = ServiceProvider.GetRequiredService<ICqrsMediator>();
            var deal = basket.GetKaskoDeal();
            var queryPrintingFormInfos = mediator.ResolveQuery<IQueryPrintingFormInfos>();

            // Используются созданные по отдельности PrintingFormInfo и вызовы методов printStoreManager для сохранения последовательности availableDocuments.
            var additionalPrintingFormInfo = queryPrintingFormInfos.GetPrintingFormInfos()
                .Where(x => x.Code == KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_KASKO_ADDITIONAL_AGREEMENT)
                .ToList();

            var statementPrintingFormInfo = queryPrintingFormInfos.GetPrintingFormInfos()
                .Where(x => x.Code == KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_KASKO_MODIFICATION_STATEMENT)
                .ToList();

            var fileTransferMethod = new FileTransferMethod
            {
                Code = settingsManager.GetSettingValue<string>("FileTransferMethod", new List<BaseEntity>() { deal, deal.Product, deal.DealIntermediaries.FirstOrDefault()?.Intermediary })
            };

            var printStores = new[]
            {
                printStoreManager.CreatePrintStores(deal, statementPrintingFormInfo, fileTransferMethod),
                printStoreManager.CreatePrintStores(deal, additionalPrintingFormInfo, fileTransferMethod)
            };

            foreach (var printStore in printStores)
            {
                printStoreManager.SavePrintStores(printStore, true);
            }
        }

        private void CapitalizePersonNames(Person person)
        {
            if (person != null)
            {
                person.LastName = person.LastName.Capitalize();
                person.Name = person.Name.Capitalize();
                person.MiddleName = person.MiddleName.Capitalize();
            }
        }

        private void UpdateTsIdentityCard(KaskoModificationTsIdentityCardModel updateTsIdentityCard, TsIdentityCard tsIdentityCard)
        {
            if (updateTsIdentityCard != null)
            {
                tsIdentityCard.isTheftDocument = updateTsIdentityCard.IsTheftDocuments;
                tsIdentityCard.Series = updateTsIdentityCard.Series ?? tsIdentityCard.Series;
                tsIdentityCard.Number = updateTsIdentityCard.Number ?? tsIdentityCard.Number;
                tsIdentityCard.TsIdentityCardTypeCode = updateTsIdentityCard.TsIdentityCardTypeCode ?? tsIdentityCard.TsIdentityCardTypeCode;
                tsIdentityCard.DateOfIssued = updateTsIdentityCard.DateOfIssued ?? tsIdentityCard.DateOfIssued;
            }
        }

        private void UpdateAuto(KaskoModificationAutoModel updateAuto, Auto auto)
        {
            if (updateAuto != null)
            {
                auto.AutoYearOfIssueCode = updateAuto.YearOfIssueCode ?? auto.AutoYearOfIssueCode;
                auto.AutoYearOfIssueValue = int.TryParse(updateAuto.YearOfIssueCode, out int year) ? year : auto.AutoYearOfIssueValue;
                auto.AutoEngineTypeCode = updateAuto.EngineTypeCode ?? auto.AutoEngineTypeCode;
                auto.AutoEnginePowerCode = updateAuto.EnginePowerCode ?? auto.AutoEnginePowerCode;
                auto.AutoEnginePowerValue = decimal.TryParse(updateAuto.EnginePowerCode, out decimal power) ? power : auto.AutoEnginePowerValue;
                auto.RegistrationNumber = updateAuto.RegNumber ?? auto.RegistrationNumber;
                auto.AutoTransmissionTypeCode = updateAuto.TransmissionTypeCode ?? auto.AutoTransmissionTypeCode;
                auto.Vin = updateAuto.Vin ?? auto.Vin;
                auto.OriginalKeysAmount = updateAuto.OriginalKeysAmount ?? auto.OriginalKeysAmount;
                auto.HasAutostart = updateAuto.HasAutostart == true ? updateAuto.HasAutostart : auto.HasAutostart;
                auto.AutoCost = updateAuto.AutoCost ?? auto.AutoCost;
                auto.IsCreditAuto = updateAuto.InCredit ?? auto.IsCreditAuto;
                auto.HasAntiTheftSystem = updateAuto.HasAntiTheftSystem ?? auto.HasAntiTheftSystem;
                auto.AutoBrandName = updateAuto.Brand ?? auto.AutoBrandName;
                auto.AutoModelName = updateAuto.Model ?? auto.AutoModelName;
                auto.ReplacingLocks = updateAuto.ReplacingLocks ?? auto.ReplacingLocks;
                UpdateAutoPurposeOfUsing(auto, updateAuto);
            }
        }

        private void UpdateAutoPurposeOfUsing(Auto auto, KaskoModificationAutoModel updateAuto)
        {
            var dictionariesCacheManager = ServiceProvider.GetRequiredService<IDictionariesCacheManager>();
            var item = dictionariesCacheManager.GetItems<PurposeOfUsing>(auto.PurposeOfUsing.VersionId).SingleOrDefault(x => x.Code == updateAuto.PurposeOfUsingCode);
            if (item == null)
            {
                AddCustomError("Недопустимые изменения: допускается передача только кода по справочнику для purposeOfUsing", ModificationErrorCodes.UnacceptableChanges);
                return;
            }

            auto.PurposeOfUsing = item;
        }

        private void UpdateDrivers(List<KaskoModificationDriverModel> updateDrivers, ObservableList<Driver> drivers)
        {
            if (updateDrivers != null)
            {
                var driversToRemove = new List<Driver>();

                foreach (var driver in drivers)
                {
                    var driverPerson = driver.GetPerson();

                    var updateDriver = updateDrivers.FirstOrDefault(ud =>
                        StringHelper.CalculateLevensteinDistance(driverPerson.Name, ud.Name) <= 2
                            && StringHelper.CalculateLevensteinDistance(driverPerson.MiddleName, ud.MiddleName) <= 2
                                && (StringHelper.CalculateLevensteinDistance(driverPerson.LastName, ud.LastName) <= 2 || ud.IsGettingMarried == true));

                    if (updateDriver != null)
                    {
                        driverPerson.LastName = updateDriver.LastName ?? driverPerson.LastName;
                        driverPerson.Name = updateDriver.Name ?? driverPerson.Name;
                        driverPerson.MiddleName = updateDriver.MiddleName ?? driverPerson.MiddleName;
                        driver.DriverLicenseNumber = updateDriver.DriverLicenseNumber ?? driver.DriverLicenseNumber;
                        driver.DriverLicenseSeries = updateDriver.DriverLicenseSeries ?? driver.DriverLicenseSeries;
                    }
                    else
                    {
                        driversToRemove.Add(driver);
                    }
                }

                driversToRemove.ForEach(d => drivers.Remove(d));

                var newDrivers = updateDrivers.Where(ud => !drivers.Any(d =>
                    d.DriverLicenseSeries == ud.DriverLicenseSeries
                        && d.DriverLicenseNumber == ud.DriverLicenseNumber));

                drivers.AddRange(newDrivers.Select(nd =>
                new Driver
                {
                    DriverLicenseSeries = nd.DriverLicenseSeries,
                    DriverLicenseNumber = nd.DriverLicenseNumber,
                    IsForeignDrivingLicense = nd.DriverIsForeignDrivingLicense,
                    DriverLicenseIssueDate = nd.DriverLicenseIssueDate,
                    Subject = new Subject
                    {
                        IndividualEntity = new IndividualEntity
                        {
                            Person = new Person
                            {
                                LastName = nd.LastName,
                                Name = nd.Name,
                                MiddleName = nd.MiddleName,
                                DateOfBirth = nd.DateOfBirth
                            }
                        }
                    },
                    DrivingExperiences = new ObservableList<DrivingExperience>
                    {
                        new DrivingExperience
                        {
                            DrivingExperienceDateStart = nd.DrivingExperienceDateStart
                        }
                    }
                }));
            }
        }

        private void UpdateInsurant(KaskoModificationPersonModel updateInsurant, Insurant insurant)
        {
            var person = insurant.GetPerson();

            UpdatePerson(updateInsurant, person);
            UpdateIdentityDocument(updateInsurant?.IdentityDocument, insurant.IdentityDocument);
        }

        private void UpdateIdentityDocument(KaskoModificationIdentityDocumentModel updateDocument, IdentityDocument document)
        {
            if (updateDocument != null)
            {
                document.Series = updateDocument.Series ?? document.Series;
                document.Number = updateDocument.Number ?? document.Number;
                document.UnitCode = updateDocument.UnitCode ?? document.UnitCode;
                document.DateIssue = updateDocument.DateIssue ?? document.DateIssue;
                document.IssuedBy = updateDocument.IssuedBy ?? document.IssuedBy;
                document.CitizenshipCode = updateDocument.CitizenshipCode ?? document.CitizenshipCode;
            }
        }

        private void UpdateOwner(KaskoModificationPersonModel updateOwner, Owner owner)
        {
            var person = owner.GetPerson();

            UpdatePerson(updateOwner, person);
            UpdateIdentityDocument(updateOwner?.IdentityDocument, owner.IdentityDocument);
        }

        private void UpdatePerson(KaskoModificationPersonModel updatePerson, Person person)
        {
            if (updatePerson != null)
            {
                person.LastName = updatePerson.LastName ?? person.LastName;
                person.Name = updatePerson.Name ?? person.Name;
                person.MiddleName = updatePerson.MiddleName ?? person.MiddleName;
                person.Email1 = updatePerson.Email ?? person.Email1;
                person.DateOfBirth = updatePerson.DateOfBirth ?? person.DateOfBirth;
                person.Age = updatePerson.DateOfBirth != null ? DurationHelper.CalculateAge(updatePerson.DateOfBirth) : person.Age;
                person.InnNumber = updatePerson.Inn ?? person.InnNumber;

                if (updatePerson.Addresses != null)
                {
                    UpdateAddresses(person.Addresses, updatePerson.Addresses);
                }
            }
        }

        private void UpdateAddresses(ObservableList<Address> addresses, List<KaskoModificationAddressModel> updateAddresses)
        {
            foreach (var address in addresses)
            {
                var updateAddress = updateAddresses
                    .FirstOrDefault(x => x.AddressTypeCode == address.AddressTypeCode);

                if (updateAddress != null)
                {
                    address.Building = updateAddress.Building ?? address.Building;
                    address.City = updateAddress.City ?? address.City;
                    address.Country = updateAddress.Country ?? address.Country;
                    address.District = updateAddress.District ?? address.District;
                    address.House = updateAddress.House ?? address.House;
                    address.Housing = updateAddress.Housing ?? address.Housing;
                    address.KladrId = updateAddress.KladrId ?? address.KladrId;
                    address.Office = updateAddress.OfficeOrFlat ?? address.Office;
                    address.Region = updateAddress.Region ?? address.Region;
                    address.Settlement = updateAddress.Settlement ?? address.Settlement;
                    address.Street = updateAddress.Street ?? address.Street;
                    address.ZipCode = updateAddress.ZipCode ?? address.ZipCode;

                    CheckAddress(address);
                }
            }
        }

        private void CheckAddress(Address address)
        {
            var daDataHelper = ServiceProvider.GetRequiredService<IDaDataHelper>();
            var updateEnteredAddress = $"{address.GetDaDataFormatedAddress()}, кв {address.Office}";
            var parsedAddress = daDataHelper.ParseAddressAsync(updateEnteredAddress, true).GetAwaiter().GetResult();

            if (parsedAddress != null)
            {
                address.Building = parsedAddress.Building ?? address.Building;
                address.City = parsedAddress.City ?? address.City;
                address.Country = parsedAddress.Country ?? address.Country;
                address.District = parsedAddress.District ?? address.District;
                address.House = parsedAddress.House ?? address.House;
                address.Housing = parsedAddress.Housing ?? address.Housing;
                address.KladrId = parsedAddress.KladrId ?? address.KladrId;
                address.Office = parsedAddress.Office ?? address.Office;
                address.Region = parsedAddress.Region ?? address.Region;
                address.Settlement = parsedAddress.Settlement ?? address.Settlement;
                address.Street = parsedAddress.Street ?? address.Street;
                address.ZipCode = parsedAddress.ZipCode ?? address.ZipCode;
                address.EnteredAddress = parsedAddress.EnteredAddress ?? address.EnteredAddress;
            }
            else
            {
                var validationResultsAggregator = ServiceProvider.GetRequiredService<IValidationResultsAggregator>();

                validationResultsAggregator.AppendValidationErrors(new ValidationError
                {
                    CriticalLevel = ValidationCriticalLevel.CantContProc,
                    ErrorMessage = "Не удалось распознать передаваемый адрес. Укажите корректный адрес или заполните KladrId."
                });
            }
        }

        /// <summary>
        /// Создаёт файловые блоки для документов сделок.
        /// </summary>
        /// <param name="basket">Корзина.</param>
        public void PrepareDocsForModifyKaskoBasket(Basket basket)
        {
            var processDataService = (IProcessDataService)ServiceProvider.GetService(typeof(IProcessDataService));
            var dictionaryDate = processDataService.GetDictionaryDate(basket.RelatedProcessKey ?? basket.Number, 1);
            var kaskoDeal = basket.GetKaskoDeal();

            var fileBlockBuilder = (IFileBlockBuilder)ServiceProvider.GetService(typeof(IFileBlockBuilder));
            var fileBlockStructureProvider = (IFileBlockStructureProvider)ServiceProvider.GetService(typeof(IFileBlockStructureProvider));
            var validationResultsAggregator = (IValidationResultsAggregator)ServiceProvider.GetService(typeof(IValidationResultsAggregator));

            // инициализация полей каско при отсутствии
            var autoKasko = kaskoDeal.GetAuto();
            var ownerKasko = kaskoDeal.GetOwner();
            kaskoDeal.AutoDeal.TsIdentityCard ??= new TsIdentityCard();
            kaskoDeal.Insurant.IdentityDocument ??= new IdentityDocument();
            ownerKasko.IdentityDocument ??= new IdentityDocument();
            kaskoDeal.OtherInsuranceCompanyPolicy ??= new OtherInsuranceCompanyPolicy();

            // Временное решение, пока не разберемся с сохранением dictionaryDate
            if (dictionaryDate == DateTime.MinValue)
            {
                dictionaryDate = DT.Now;
            }

            // создаём файловые блоки
            if (kaskoDeal.AutoDeal.Drivers.Any(dr => dr.DriverLicenseScan is null))
            {
                fileBlockBuilder.BuildFileBlock(
                    basket,
                    fileBlockStructureProvider.GetFileBlockStructure("DriverLicense", dictionaryDate),
                    "Deals.Where(Product.InsuranceTypeCode == \"KASKO\").AutoDeal.Drivers.DriverLicenseScan");
            }

            if (kaskoDeal.AutoDeal.TsIdentityCard.FileBlock is null || kaskoDeal.AutoDeal.TsIdentityCard.FileBlock.FileGroups.Count == 0)
            {
                fileBlockBuilder.BuildFileBlock(
                    basket,
                    fileBlockStructureProvider.GetFileBlockStructure(nameof(TsIdentityCard), dictionaryDate),
                    "Deals.Where(Product.InsuranceTypeCode == \"KASKO\").AutoDeal.TsIdentityCard.FileBlock");

                if (kaskoDeal.AutoDeal.TsIdentityCard.OwnershipProof is null || kaskoDeal.AutoDeal.TsIdentityCard.OwnershipProof.FileGroups.Count == 0)
                {
                    fileBlockBuilder.BuildFileBlock(
                            basket,
                            fileBlockStructureProvider.GetFileBlockStructure("OwnershipProof", dictionaryDate),
                            "Deals.Where(Product.InsuranceTypeCode == \"KASKO\").AutoDeal.TsIdentityCard.OwnershipProof");
                }
            }

            if (kaskoDeal.Insurant.IdentityDocument.FileBlock is null || kaskoDeal.Insurant.IdentityDocument.FileBlock.FileGroups.Count == 0)
            {
                fileBlockBuilder.BuildFileBlock(
                    basket,
                    fileBlockStructureProvider.GetFileBlockStructure(nameof(IdentityDocument), dictionaryDate),
                    "Deals.Where(Product.InsuranceTypeCode == \"KASKO\").Insurant.IdentityDocument.FileBlock");
            }

            if (ownerKasko.IdentityDocument.FileBlock is null)
            {
                fileBlockBuilder.BuildFileBlock(
                    basket,
                    fileBlockStructureProvider.GetFileBlockStructure(nameof(IdentityDocument), dictionaryDate),
                    "Deals.Where(Product.ProductDictCode == \"KASKO\").InsuranceObjects.Where(InsuranceObjectTypeCode == \"Auto\").Owners[0].IdentityDocument.FileBlock");
            }

            if (kaskoDeal.OtherInsuranceCompanyPolicy.FileBlock is null)
            {
                fileBlockBuilder.BuildFileBlock(
                    basket,
                    fileBlockStructureProvider.GetFileBlockStructure("InsuranceCaseOther", dictionaryDate),
                    "Deals.Where(Product.ProductDictCode == \"KASKO\").OtherInsuranceCompanyPolicy.FileBlock");
            }
        }

        public void SetRequiredForFileBlocks(Basket basket, ModificationChangesResult changesResult)
        {
            var changes = getAllChanges(changesResult.Changes.ChangesDictionary);

            CheckAndSetMinFilesCountForTsDocuments(basket, changes);
            CheckAndSetMinFilesCountForInsurantDocuments(basket, changes);
            CheckAndSetMinFilesCountForOwnerDocuments(basket, changes);
            CheckAndSetMinFilesCountForDriverDocuments(basket, changes);
            CheckAndSetMinFilesCountForPtsDocuments(basket, changes);
        }

        private List<string> getAllChanges(Dictionary<string, List<ObjectCompareResult>> changesDictionary)
        {
            var keysToCheck = new[]
            {
                "AutoDeal.Drivers",
                "InsuranceObjects[0].Auto",
                "AutoDeal",
                "Insurant",
                "InsuranceObjects[0].Owners[0]"
            };

            var changes = keysToCheck
                .Where(key => changesDictionary.TryGetValue(key, out var results) && results.Count > 0)
                .SelectMany(key => changesDictionary[key].SelectMany(result => result.ChangedFields))
                .ToList();

            return changes;
        }

        private void CheckAndSetMinFilesCountForTsDocuments(Basket basket, List<string> changes)
        {
            if (changes.Contains(ChangesPaths.AutoDocNumber) || changes.Contains(ChangesPaths.AutoDocSeries) || changes.Contains(ChangesPaths.AutoDocDateOfIssued) || changes.Contains(ChangesPaths.AutoRegistrationNumber) || changes.Contains(ChangesPaths.AutoYearOfIssueCode) || changes.Contains(ChangesPaths.AutoEnginePowerCode) || changes.Contains(ChangesPaths.AutoVin))
            {
                SetMinFilesCountForTsDocuments(basket);
            }
        }

        private void CheckAndSetMinFilesCountForInsurantDocuments(Basket basket, List<string> changes)
        {
            if (changes.Contains(ChangesPaths.InsurantEnteredAddress0) || changes.Contains(ChangesPaths.InsurantEnteredAddress1) || changes.Contains(ChangesPaths.InsurantEnteredAddress2)
                || changes.Contains(ChangesPaths.InsurantName) || changes.Contains(ChangesPaths.InsurantMiddleName) || changes.Contains(ChangesPaths.InsurantLastName)
                || changes.Contains(ChangesPaths.InsurantDateOfBirth) || changes.Contains(ChangesPaths.InsurantIdentityDocumentSeries)
                || changes.Contains(ChangesPaths.InsurantIdentityDocumentNumber) || changes.Contains(ChangesPaths.InsurantIdentityDocumentType) || changes.Contains(ChangesPaths.InsurantIdentityDocumentUnitCode)
                || changes.Contains(ChangesPaths.InsurantIdentityDocumentDateIssue) || changes.Contains(ChangesPaths.InsurantIdentityDocumentIssuedBy))
            {
                SetMinFilesCountForInsurantDocuments(basket);
            }
        }

        private void CheckAndSetMinFilesCountForOwnerDocuments(Basket basket, List<string> changes)
        {
            if (changes.Contains(ChangesPaths.OwnerEnteredAddress0) || changes.Contains(ChangesPaths.OwnerEnteredAddress1) || changes.Contains(ChangesPaths.OwnerEnteredAddress2)
                || changes.Contains(ChangesPaths.OwnerName) || changes.Contains(ChangesPaths.OwnerMiddleName) || changes.Contains(ChangesPaths.OwnerLastName)
                || changes.Contains(ChangesPaths.OwnerDateOfBirth) || changes.Contains(ChangesPaths.OwnerIdentityDocumentSeries)
                || changes.Contains(ChangesPaths.OwnerIdentityDocumentNumber) || changes.Contains(ChangesPaths.OwnerIdentityDocumentType)
                || changes.Contains(ChangesPaths.OwnerIdentityDocumentUnitCode) || changes.Contains(ChangesPaths.OwnerIdentityDocumentDateIssue)
                || changes.Contains(ChangesPaths.OwnerIdentityDocumentIssuedBy))
            {
                SetMinFilesCountForOwnerDocuments(basket);
            }
        }

        private void CheckAndSetMinFilesCountForDriverDocuments(Basket basket, List<string> changes)
        {
            if (changes.Contains(ChangesPaths.DriverName) || changes.Contains(ChangesPaths.DriverMiddleName) || changes.Contains(ChangesPaths.DriverLastName))
            {
                SetMinFilesCountForDriverDocuments(basket, changes);
            }
        }

        private void CheckAndSetMinFilesCountForPtsDocuments(Basket basket, List<string> changes)
        {
            if (changes.Contains(ChangesPaths.AutoDocSeries) || changes.Contains(ChangesPaths.AutoDocNumber))
            {
                SetMinFilesCountForPtsDocuments(basket);
            }
        }

        private void SetMinFilesCountForTsDocuments(Basket basket)
        {
            basket.GetKaskoDeal().AutoDeal.TsIdentityCard.FileBlock.FileGroups.FirstOrDefault(f => f.Name == "TsDocuments").MinFilesCount = 1;
        }

        private void SetMinFilesCountForInsurantDocuments(Basket basket)
        {
            basket.GetKaskoDeal().Insurant.IdentityDocument.FileBlock.FileGroups.FirstOrDefault(f => f.Name == "Documents").MinFilesCount = 1;
        }

        private void SetMinFilesCountForOwnerDocuments(Basket basket)
        {
            basket.GetKaskoDeal().GetOwner().IdentityDocument.FileBlock.FileGroups.FirstOrDefault(f => f.Name == "Documents").MinFilesCount = 1;
        }

        private void SetMinFilesCountForDriverDocuments(Basket basket, List<string> changes)
        {
            var groups = basket.GetKaskoDeal().AutoDeal.Drivers.SelectMany(d => d.DriverLicenseScan.FileGroups.Where(f => f.Name == "DriverDocuments")).ToArray();
            var changedDriversCount = changes.Where(x => x == ChangesPaths.DriverPersonState).Count();

            for (int i = 0; i < changedDriversCount; i++)
            {
                groups[i].MinFilesCount = 1;
            }
        }

        private void SetMinFilesCountForPtsDocuments(Basket basket)
        {
            basket.GetKaskoDeal().AutoDeal.TsIdentityCard.FileBlock.FileGroups.FirstOrDefault(f => f.Name == "TsDocuments").MinFilesCount = 1;
        }

        public CdpPackage CreateDocumentsPack(Basket basket)
        {
            var feFinder = ServiceProvider.GetRequiredService<IFileEntityFinder>();
            var fileBlocks = feFinder.FindFileBlocks(new[] { basket.GetKaskoDeal() });

            var insurantPerson = basket.Deals.FirstOrDefault(d => d.Insurant != null)?.Insurant?.Subject?.IndividualEntity?.Person;

            var filesBlocks = fileBlocks
                .Where(b => (b.FileEntity.ObjectInstance as FileBlock).FileGroups
                .Any(g => g.MinFilesCount > 0 && g.FileInfos.Any()))
                .Select(b => b.FileEntity.ObjectInstance as FileBlock)
                .ToList();

            var cdpPackage = new CdpPackage
            {
                CreateDate = DT.Now,
                PolicyNumber = basket.GetKaskoDeal().PolicyNumber,
                Phone = insurantPerson.Phone1,

                ClientFullName = insurantPerson.GetFullName(),
                Status = (int)CdpPackageStates.Added
            };

            foreach (var block in filesBlocks)
            {
                cdpPackage.Documents.Add(new Document
                {
                    FileBlock = block
                });
            }

            return cdpPackage;
        }

        public void AddCustomError(string error, string code)
        {
            ((IValidationResultsAggregator)ServiceProvider.GetService(typeof(IValidationResultsAggregator))).AppendValidationErrors(new ValidationError
            {
                ErrorMessage = $"Код: {code}. {error}.",
                CriticalLevel = ValidationCriticalLevel.CantContProc
            });
        }

        public bool CheckKaskoPolicyModificationAllowed(string integrationLogin)
        {
            var settingsManager = ServiceProvider.GetRequiredService<IEntitySettingsManager>();

            return settingsManager.GetSettingForDefaultOrPartnerConfiguration(
                iRIS.KaskoLink2.Implementations.Code.Constants.EntitySettingCodes.KaskoPolicyModificationAllowed,
                iRIS.KaskoLink2.Implementations.Code.Constants.EntitySettingCodes.KaskoPolicyModificationAllowedDefault,
                iRIS.KaskoLink2.Implementations.Code.Constants.EntitySettingCodes.KaskoPolicyModificationAllowedPartner,
                new IntegrationLogin { IntegrationLoginName = integrationLogin },
                false);
        }

        public void SetSignDateToDeal(Basket basket)
        {
            var deal = basket.GetKaskoDeal();
            deal.DateSign = DT.Now;
        }

        /// <summary>
        /// Производится фильтрация документов, добавляется заявление если требуется.
        /// </summary>
        /// <param name="inputDocument">Дополнительное соглашение.</param>
        /// <param name="basket">Корзина.</param>
        /// <returns>Список документов для печати.</returns>
        public List<DocumentInfo> FilterPrintDocuments(DocumentInfo inputDocument, Basket basket)
        {
            List<DocumentInfo> outputDocuments = new List<DocumentInfo>();
            var deal = basket.GetKaskoDeal();

            if (deal.AutoDeal?.TsIdentityCard?.isTheftDocument == true &&
            deal.AutoDeal?.TsIdentityCard?.TsIdentityCardTypeCode == "pts")
            {
                outputDocuments.Add(inputDocument);

                var printingActivityHelper = new PrintingActivityHelper();
                var additionalDocument = printingActivityHelper.PrintDocument(ServiceProvider, KaskoOsagoPrintingFormCodes.PRINTING_FORM_CODE_KASKO_MODIFICATION_STATEMENT, basket, false, null);
                outputDocuments.Add(additionalDocument);
            }
            else
            {
                outputDocuments.Add(inputDocument);
            }

            return outputDocuments;
        }
    }
}

Что делает код?