using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using iRIS.Framework.Common;
using iRIS.Framework.CrossCutting.Caching;
using iRIS.Framework.Data.Services.Client.Interfaces;
using iRIS.Framework.Link2;
using iRIS.Framework.Link2.AppServices.Link2ProcessAccessCheck;
using iRIS.Framework.Link2.Extensions;
using iRIS.Framework.RequestPipeline.Abstractions;
using iRIS.Framework.RequestPipeline.Extensions;
using iRIS.Framework.RequestPipeline.Pipelines;
using iRIS.Framework.Workflow.Data;
using iRIS.InsuranceCore.Code.CustomProcesses.BasketPreparationProcess.Enums;
using iRIS.InsuranceCore.Code.Interfaces;
using iRIS.InsuranceCore.Code.Interfaces.Clients.ViewAppServiceClient.Constants;
using iRIS.InsuranceCore.Code.Queries;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.InsuranceCore.Entities.Enums;
using iRIS.KaskoCore.Code.Constants;
using iRIS.KaskoCore.Code.Queries;
using iRIS.KaskoLink2.Code.Constants;
using iRIS.KaskoLink2.Code.Implementations.PreInsuranceCheck;
using iRIS.KaskoLink2.Code.Link2;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using EntityContextKeys = iRIS.KaskoCore.Code.Constants.EntityContextKeys;

namespace iRIS.KaskoLink2.Code.Extensions.Link2
{
    [PipelineStage(PipelineStage.PreOperation)]
    internal class DiKaskoLink2BasketInitializationPreOperationExtension : IPipelineExtension
    {
        private readonly string[] _allowedUrmApprovalStatuses = { UrmApprovalStatusCodes.NotRequired, UrmApprovalStatusCodes.Required };
        private readonly string[] _allowedOtaApprovalStatuses = { OtaApprovalStatusCodes.NotRequired, OtaApprovalStatusCodes.Required };
        private readonly string[] _notAllowedUnderwriterApprovalStatuses = { DiUnderwriterApprovalStatusCodes.InWork, DiUnderwriterApprovalStatusCodes.RequiredExtraInfo };
        private readonly string[] _underwriterRejectThemes =
        {
            DIUnderwriterApprovalThemeCodes.VehCostIsAboveRangeForLink2,
            DIUnderwriterApprovalThemeCodes.Link2AntiTheftDevice,
            DIUnderwriterApprovalThemeCodes.Link2IncompSetOfKeys,
            DIUnderwriterApprovalThemeCodes.Link2Other
        };

        public bool CanExecute(IPipelineContext pipelineContext)
        {
            var serviceProvider = pipelineContext.ServiceProvider;
            var processApiContext = serviceProvider.GetRequiredService<ProcessApiContext>();
            var context = serviceProvider.GetRequiredService<PipelineExecutionContext>();

            return processApiContext.Command is DIKaskoCalculationLink2Command
                   && !context.Entities.ContainsKey("Basket")
                   && processApiContext.InputParameters.ContainsKey("previousBasketNumber");
        }

        public void Execute(IPipelineContext pipelineContext)
        {
            var serviceProvider = pipelineContext.ServiceProvider;
            var cacheReflectionManager = (ICacheReflectionManager)serviceProvider.GetService(typeof(ICacheReflectionManager));
            var link2EntityAccessCheckService = serviceProvider.GetRequiredService<ILink2EntityAccessCheckService>();
            var cachedQueryService = serviceProvider.GetRequiredService<ICachedQueryServiceInvoker>();
            var logger = serviceProvider.GetRequiredService<ILogger>();
            var queryKaskoInspection = serviceProvider.GetRequiredService<IQueryKaskoInspection>();

            var processApiContext = serviceProvider.GetRequiredService<ProcessApiContext>();
            var context = serviceProvider.GetRequiredService<PipelineExecutionContext>();

            if (!processApiContext.InputParameters.TryGetValue("previousBasketNumber", out var previousBasketNumber))
            {
                return;
            }

            var timer = Stopwatch.StartNew();
            var cachedBasket = GetBasketFromCache(previousBasketNumber, pipelineContext);
            var previousBasket = cachedBasket ?? GetBasketFromDb(previousBasketNumber, pipelineContext);

            timer.Stop();
            logger
                .ForContext("ProcessKey", previousBasket.Number)
                .Information($"Корзина получена из {(cachedBasket != null ? "кэша" : "БД")} за {timer.ElapsedMilliseconds} ms");

            if (previousBasket != null)
            {
                var basketEntityId = previousBasket.EntityId;
                if (basketEntityId > 0 && !link2EntityAccessCheckService.CheckPermissionAccessToEntity(basketEntityId, "Basket", processApiContext))
                {
                    processApiContext.EndPipelineWithLink2ErrorResponse(Link2MessageCodesBase.AuthorizationError, "Ошибка доступа к корзине.", cacheReflectionManager);
                    return;
                }

                var deal = previousBasket.GetKaskoDeal();
                if (deal != null)
                {
                    if (deal.DealStatusCode == EntityStatusType.PolicyIssued.ToString() ||
                        deal.DealStatusCode == EntityStatusType.Signed.ToString())
                    {
                        processApiContext.EndPipelineWithLink2ErrorResponse(Link2MessageCodesBase.ValidationError, "Перерасчет не возможен, полис оформлен.", cacheReflectionManager);
                        return;
                    }

                    if (deal.AutoDeal.TryGetLastUrmApproval(out var urmapproval) &&
                        !_allowedUrmApprovalStatuses.Contains(urmapproval.URMApprovalStatusCode))
                    {
                        processApiContext.EndPipelineWithLink2ErrorResponse(Link2MessageCodesBase.ValidationError, "Перерасчет не возможен, проверки УРМ.", cacheReflectionManager);
                        return;
                    }

                    var approval = deal.AutoDeal?.DIUnderwriterApprovals?.FirstOrDefault(d =>
                        _notAllowedUnderwriterApprovalStatuses.Contains(d.StatusCode) ||
                        HasUnderwriterRejectThemes(d.StatusCode, d.ThemeCode));

                    if (approval != null)
                    {
                        processApiContext.EndPipelineWithLink2ErrorResponse(Link2MessageCodesBase.ValidationError, "Перерасчет не возможен, проверки андеррайтинга.", cacheReflectionManager);
                        return;
                    }

                    if (deal.AutoDeal.TryGetLastOtaApproval(out var otaapproval) &&
                        !_allowedOtaApprovalStatuses.Contains(otaapproval.OtaApprovalStatusCode))
                    {
                        processApiContext.EndPipelineWithLink2ErrorResponse(Link2MessageCodesBase.ValidationError, "Перерасчет не возможен, проверки ОТА.", cacheReflectionManager);
                        return;
                    }

                    var inspection = queryKaskoInspection.GetInspectionByDealEntityId(deal.EntityId);
                    if (inspection?.InspectionStatusCode == InspectionStatusConstants.Draft && HasPsoSentToClient(previousBasket, deal))
                    {
                        processApiContext.EndPipelineWithLink2ErrorResponse(Link2MessageCodesBase.ValidationError, "Перерасчет не возможен, проверки ПСО.", cacheReflectionManager);
                        return;
                    }
                }

                previousBasket.EntityContext.AddOrUpdate(EntityContextKeys.IsExternalBasket, true);
                context.ProcessCustomInputData.AddOrUpdate("ExternalBasket", previousBasket);
                logger
                    .ForContext("ProcessKey", previousBasket.Number)
                    .Information($"Перерасчет с номером корзины {previousBasket.Number}.");
            }
        }

        private Basket GetBasketFromDb(string basketNumber, IPipelineContext pipelineContext)
        {
            var queryBasket = pipelineContext.ServiceProvider.GetService<IQueryBasket>();
            var basket = queryBasket.GetCurrentBasketByNumberIfExists(basketNumber, Link2AggregateNames.Link2KaskoBasket, true);

            return basket;
        }

        private Basket GetBasketFromCache(string basketNumber, IPipelineContext pipelineContext)
        {
            var basketNumberProcessKeyAccessor = pipelineContext.ServiceProvider.GetRequiredService<IBasketNumberProcessKeyAccessor>();

            if (basketNumberProcessKeyAccessor.TryGetProcessKeyByBasketNumber(basketNumber, out var processKey))
            {
                var cache = pipelineContext.ServiceProvider.GetRequiredService<ICache>();
                var processRelationService = pipelineContext.ServiceProvider.GetRequiredService<IProcessRelationService>();
                var processInfo = processRelationService.GetProcessInfo(processKey, 1);
                var cachedEntities = cache.Get<Dictionary<string, object>>($"{processInfo.Guid}_entities");

                if (cachedEntities?.TryGetValue("DiKaskoInsurance:Basket", out Basket basket) == true)
                {
                    return basket;
                }
            }

            return null;
        }

        private bool HasPsoSentToClient(Basket basket, Deal deal)
        {
            if (basket.EntityContext.TryGetValue(nameof(PreInsuranceCheckModel), out PreInsuranceCheckModel preInsuranceCheckModel))
            {
                return preInsuranceCheckModel.Status == PreInsuranceCheckStatuses.InWork;
            }

            if (deal.EntityContext.TryGetValue(PsoEntityValuesConstants.IsPsoInWork, out bool isInWork))
            {
                return isInWork;
            }

            return false;
        }

        private bool HasUnderwriterRejectThemes(string statusCode, string themeCode)
        {
            return statusCode == DiUnderwriterApprovalStatusCodes.Rejected &&
                   _underwriterRejectThemes.Contains(themeCode);
        }
    }
}


Совпадает ли логика в коде с данной:
Перерасчет доступен для любого underwriterApprovalStatus кроме Inwork и requiredExtraInfo, при условии, что для проверок УРМ и ОТА статус = required, notRequired, null, а ПСО = draft, не разделенный с пользователем. Примечание: за разделение осмотра с пользователем отвечает техническая переменная, которая ставится в inWork.