using iRIS.Framework.Entity.Dictionary.LocalDictionaryCache;
using iRIS.Framework.Entity.Metadata;
using iRIS.Framework.Validation;
using iRIS.Framework.Workflow.Process.CustomProcessModel;
using iRIS.Framework.Workflow.UserData;
using iRIS.InsuranceApp.Infrastructure.Constants;
using iRIS.InsuranceCore.Code.Implementations.AisIntegrationService;
using iRIS.InsuranceCore.Code.Interfaces.AisIntegrationService;
using iRIS.InsuranceCore.Code.Interfaces.AisIntegrationService.Models;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.InsuranceCore.Entities.Enums;
using Microsoft.Extensions.DependencyInjection;
using Serilog;
using System;
using System.Collections.Generic;
using System.Linq;

namespace iRIS.KaskoLink2.Code.CustomProcesses
{
    public class GetKaskoCommissionsWithSegmentProcess : ICustomProcess
    {
        public const string InputArgument_BasketNumber = nameof(BasketNumber);
        public const string InputArgument_AuthorizationData = nameof(AuthorizationData);
        public const string InputArgument_Deals = nameof(Deals);
        public const string InputArgument_UseDrafts = nameof(UseDrafts);

        public InputArgument<string> BasketNumber { get; } = new InputArgument<string>(InputArgument_BasketNumber);

        public InputArgument<AuthorizationData> AuthorizationData { get; } = new InputArgument<AuthorizationData>(InputArgument_AuthorizationData);

        public InputArgument<List<Deal>> Deals { get; } = new InputArgument<List<Deal>>(InputArgument_Deals);

        public InputArgument<bool> UseDrafts { get; } = new InputArgument<bool>(InputArgument_UseDrafts);

        private AuthorizationData _authorizationData;
        private string _basketNumber;
        private List<Deal> _deals;
        private bool _useDrafts;
        private string _requestedCommissionDiscount;
        private IAisIntegrationClient _aisIntegrationClient;
        private IAISProductGetter _aisProductGetter;
        private IDictionariesCacheManager _dictionariesCacheManager;
        private ILogger _logger;
        private IActualizeDealIntermediary _actualizeDealIntermediary;
        private IValidationResultsAggregator _validationResultsAggregator;

        public void Execute(IProcessContext processContext)
        {
            InitializeCustomProcessVariables(processContext);
            LogProcessStart();

            var dealWithIntermediary = _deals
                .Single(d => d.DealIntermediaries.Count > 0 && d.Product.ProductDictCode == ProductDictCodes.Kasko);

            _actualizeDealIntermediary.Actualize(_authorizationData, dealWithIntermediary);

            GetDealCommissionsWithSegment(dealWithIntermediary);
        }

        private void GetDealCommissionsWithSegment(Deal deal)
        {
            var dealIntermediaries = GetFilteredIntermediaries(deal);

            if (dealIntermediaries.Count == 0)
            {
                return;
            }

            var mapper = AisCommissionsMapperFactory.CreateMapper(deal.Product.ProductDictCode);
            var agentInfos = mapper.GetAgentInfos(dealIntermediaries, deal.Product);

            var proposal = deal.GetSelectedProposal();
            var aisProduct = _aisProductGetter.GetAISProductByOfferId(proposal.Offer_Id.Value, _useDrafts);

            var request = mapper.GetCommissionsWithSegmentRequest(_basketNumber, deal, agentInfos, aisProduct);

            var response = _aisIntegrationClient.GetCommissionsWithSegment(request);

            switch (response?.Status)
            {
                case StatusType.Success:
                    ProcessResponse(response, deal);
                    ProcessCommissionDiscount(response, deal);
                    ProcessLoadCoefficient(response, deal);
                    break;
                case StatusType.NoRequest:
                    ProcessLoadCoefficient(response, deal);
                    break;
                case StatusType.Error:
                default:
                    SetZeroCommissionDiscount(deal);
                    ProcessLoadCoefficient(response, deal);
                    break;
            }
        }

        /// <summary>
        /// Фильтрация посредников перед отправкой в Commissions: 
        /// 1. берем тех, у кого заполнен CashbookId; 
        /// 2. убираем "фиктивных" агентов: Фиктивный агент должен иметь связь с посредником-родителем Брокером и CashbookId у них совпадают.
        /// </summary>
        private List<DealIntermediary> GetFilteredIntermediaries(Deal deal)
        {
            var brokerIntermediaries = deal.DealIntermediaries
                .Where(di => di.Intermediary.InteractionTypeCode == InteractionTypeEnum.Broker.ToString())
                .ToList();

            var dealIntermediaries = deal.DealIntermediaries
                .Where(di => !string.IsNullOrWhiteSpace(di.Intermediary.CashbookId))
                .Where(di => !(di.Intermediary.InteractionTypeCode == InteractionTypeEnum.Agent.ToString()
                    && brokerIntermediaries.Any(bi => bi.Intermediary.CashbookId == di.Intermediary.CashbookId && bi.Intermediary.Id == di.Intermediary.ParentIntermediary_Id)))
                .ToList();

            return dealIntermediaries;
        }

        private void ProcessResponse(CommissionsWithSegmentResponse response, Deal deal)
        {
            // Сохраняем общее КВ по полису
            deal.GetSelectedProposal().CommisionValue = response.TotalKvOriginal;

            // Если Commissions вернул в ответе посредника с CashbookID, которого нет среди посредников в сделке, то записываем его в DealIntermediary
            // Сохраняем размер КВ по каждому посреднику
            _actualizeDealIntermediary.ActualizeByCommissionsResponse(response, deal);
        }

        private void ProcessCommissionDiscount(CommissionsWithSegmentResponse response, Deal deal)
        {
            if (!string.IsNullOrEmpty(_requestedCommissionDiscount))
            {
                var mainIntermediary = deal.DealIntermediaries.Single(di => di.IsMain == true);
                var discount = decimal.Parse(_requestedCommissionDiscount);
                if (IsRequestedKvDiscountGreater(mainIntermediary, discount))
                {
                    AddValidationError("Внимание! Скидка за счет КВ превышает допустимое значение. Исправьте значение и повторите расчет.");
                }
                else
                {
                    ApplyRequestedDiscountToMainIntermediary(mainIntermediary, discount);
                    SetDiscountToDeal(deal, discount);
                }
            }
        }

        private void ProcessLoadCoefficient(CommissionsWithSegmentResponse response, Deal deal)
        {
            if (response?.Kcomission == null)
            {
                return;
            }

            deal.AutoDeal.LoadCoefficient = response.Kcomission;
        }

        private void AddValidationError(string errorMessage)
        {
            _validationResultsAggregator.AppendValidationErrors(new ValidationError
            {
                CriticalLevel = ValidationCriticalLevel.CantContProc,
                ErrorMessage = errorMessage
            });
        }

        /// <summary>
        /// Установка значения скидки за счет КВ для последующего пересчета стоимости с ее учетом.
        /// </summary>
        private void SetDiscountToDeal(Deal deal, decimal discount)
        {
            var selectedDiscountCombination = deal.GetSelectedDiscountCombination();
            var dealDiscount = selectedDiscountCombination.Discounts.SingleOrDefault(d =>
                d.CalculationComponentCoefficient.Coefficient.Name.Equals("K_Commission_Fee", StringComparison.OrdinalIgnoreCase));

            if (dealDiscount == null)
            {
                return;
            }

            selectedDiscountCombination.DiscountCombinationStatusCode = DiscountCombinationStatuses.Agreed;
            dealDiscount.DiscountSwitchOnOff = true;
            dealDiscount.DiscountValue = 1 - (discount / 100);
        }

        /// <summary>
        /// Расчет окончательного КВ: 
        /// если основной посредник работает с компенсацией, то рассчитать окончательное КВ по формуле: КВ% = ((КВ% - Скидка%) / (100% - Скидка%)) * 100.
        /// если основной посредник работает без компенсации, то рассчитать окончательное КВ по формуле: КВ% = КВ% - Скидка%.
        /// </summary>
        private void ApplyRequestedDiscountToMainIntermediary(DealIntermediary dealIntermediary, decimal requestedDiscountCommission)
        {
            if (dealIntermediary.Intermediary.WorkWithCompensation == true)
            {
                var cv = (dealIntermediary.CommisionValue - requestedDiscountCommission) / (100 - requestedDiscountCommission) * 100;
                dealIntermediary.CommisionValue = Math.Round(cv.Value, 2);
            }
            else
            {
                dealIntermediary.CommisionValue -= requestedDiscountCommission;
            }
        }

        /// <summary>
        /// Превышает ли размер скидки, присланный партнером, CommisionValue посредника с IsMain.
        /// </summary>
        private bool IsRequestedKvDiscountGreater(DealIntermediary dealIntermediary, decimal requestedDiscountCommission)
        {
            return requestedDiscountCommission > dealIntermediary.CommisionValue.Value;
        }

        /// <summary>
        /// Установка нулевого КВ в случае отсутствия ответа от АИС.
        /// </summary>
        private void SetZeroCommissionDiscount(Deal deal)
        {
            var mainIntermediary = deal.DealIntermediaries.Single(di => di.IsMain == true);
            mainIntermediary.CommisionValue = 0;
        }

        private void InitializeCustomProcessVariables(IProcessContext processContext)
        {
            _basketNumber = BasketNumber.Get(processContext);
            _useDrafts = UseDrafts.Get(processContext);
            _deals = Deals.Get(processContext);
            _authorizationData = AuthorizationData.Get(processContext);
            _requestedCommissionDiscount = processContext.GetCustomVariable("CommissionDiscount")?.ToString();

            _dictionariesCacheManager = processContext.ServiceProvider.GetRequiredService<IDictionariesCacheManager>();
            _aisIntegrationClient = processContext.ServiceProvider.GetRequiredService<IAisIntegrationClient>();
            _aisProductGetter = processContext.ServiceProvider.GetRequiredService<IAISProductGetter>();
            _logger = processContext.ServiceProvider.GetRequiredService<ILogger>().ForContext<GetKaskoCommissionsWithSegmentProcess>();
            _actualizeDealIntermediary = processContext.ServiceProvider.GetRequiredService<IActualizeDealIntermediary>();
            _validationResultsAggregator = processContext.ServiceProvider.GetRequiredService<IValidationResultsAggregator>();
        }

        private void LogProcessStart()
        {
            _logger
                .ForContext("ProcessKey", _basketNumber)
                .Information($"Запуск процесса {nameof(GetKaskoCommissionsWithSegmentProcess)} получения КВ для посредников сделок.");
        }
    }
}

Есть ли тут какое то условие когда мы получаем коэффициент, а когда нет?