using iRIS.Framework.Entity.Dictionary.EntitySettings;
using iRIS.InsuranceCore.Code.Implementations;
using iRIS.InsuranceCore.Entities;
using iRIS.InsuranceCore.Entities.EntityExtensions;
using iRIS.InsuranceCore.Infrastructure.Constants;
using iRIS.InsuranceCore.OSS.Code.Constants;
using iRIS.InsuranceCore.OSS.Code.Dto.Uni;
using iRIS.InsuranceCore.OSS.Code.Mappers;
using iRIS.InsuranceCore.OSS.Code.Mappers.CoversMapper;
using iRIS.KaskoCore.OSS.Code.Constants;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;

namespace iRIS.KaskoCore.OSS.Code.Mappers
{
    public class KaskoCoversMapper : BaseCoversMapper
    {
        /// <summary>
        /// Код ОСС для обозначения типа ограничения "покрытие".
        /// </summary>
        private const string CoverageOssType = "2";

        private readonly IEntitySettingsManager _entitySettingsManager;

        public KaskoCoversMapper(IEntitySettingsManager entitySettingsManager)
        {
            _entitySettingsManager = entitySettingsManager;
        }

        protected override void MapCoverages(List<OssUniCoverDto> propertyDto, Deal deal, DealCoverage[] coverages, List<string> options)
        {
            //спецефическая логика расчета суммы покрытия допрасходов (не поддерживается DealConditionProcessor)
            var addCostsCover = coverages.FirstOrDefault(cov => cov.ProductCoverage.CoverageCode == CoverageCodes.ADDCOSTS);
            if (addCostsCover != null)
            {
                var conditionsBlocks = new List<ConditionBlock>
                {
                    addCostsCover.ConditionBlock
                };
                conditionsBlocks.AddRange(addCostsCover.DealRisks
                    .Where(dr => dr != null)
                    .Select(dr => dr.ConditionBlock));

                var addCostsOptions = conditionsBlocks
                    .Where(x => x != null)
                    .SelectMany(x => x.DealOptions)
                    .Where(x => x != null)
                    .GroupBy(o => o.Id).Select(g => g.First())
                    .Where(d => d.Sum.HasValue);

                addCostsCover.Sum = addCostsOptions.Sum(o => o.Sum.Value);
            }

            var destributedCovers = ProportionalPremiumDistributor.GetDestributedCoveragePremimums(deal);

            var ci = new CultureInfo(OssConstants.CultureInfoName);
            foreach (var coverage in coverages)
            {
                var restrictions = new List<OssUniRestrictionDto>
                {
                    new OssUniRestrictionDto
                    {
                        Name = MapHelper.MapForDictionaryKey(coverage.ProductCoverage.CoverageCode, MapDictionarys.ProductCodeToOssRestrictionName),
                        Type = CoverageOssType,
                        Value = KaskoDetermineCoverageSum(coverage, ci),
                        Currency = OssConstants.Currency
                    }
                };
                restrictions.AddRange(coverage.DealRisks.SelectMany(x => x.ConditionBlock?.DealFranchises ?? new List<DealFranchise>())
                    .Where(x => x != null)
                    .Select(x => new OssUniRestrictionDto
                    {
                        Name = MapHelper.MapForDictionaryKey(x.ProductFranchise.Code, MapDictionarys.ProductCodeToOssRestrictionName),
                        Type = MapHelper.MapForDictionaryKey(x.ProductFranchise.Code, MapDictionarys.ProductCodeToOssRestrictionType),
                        Value = x.Sum.HasValue ? x.Sum.Value.ToString(OssConstants.SumFormat, ci) : "0",
                        Currency = OssConstants.Currency
                    }));

                if (coverage.ProductCoverage.CoverageCode == CoverageCodes.AUTOKASKO && coverage.DealRisks.Any(r => r.ProductRisk.RiskCode == RiskCodes.DAMAGE))
                {
                    var offerId = deal.GetSelectedProposal().Offer_Id;

                    restrictions.Add(new OssUniRestrictionDto
                    {
                        Name = OssRestrictionNames.FranchiseAutoKasko,
                        Type = "4",
                        Value = GetRestrictionValueForOffer(offerId),
                        Currency = OssConstants.Currency
                    });
                }

                var cover = new OssUniCoverDto
                {
                    Code = MapHelper.MapForDictionaryKey(coverage.ProductCoverage.CoverageCode, MapDictionarys.ProductCoverageCodeToOssCoverCodeMapping),
                    Premium = ProportionalPremiumDistributor.GetDestributedPremimum(destributedCovers, coverage.ProductCoverage.CoverageCode),
                    Risks = coverage.DealRisks.SelectMany(x => MapForDictionaryStrArr(x.ProductRisk.RiskCode, MapDictionarys.ProductRiskCodeToOssRiskCodeMapping)).Distinct().ToList(),
                    Restrictions = restrictions
                };

                if (cover.Code == "AC")
                {
                    cover.Risks.Clear();
                    if (options.Contains(OptionCodes.TAXI))
                    {
                        cover.Risks.Add(OssRiskCodes.TAXI);
                    }

                    if (options.Contains(OptionCodes.EVACUATION))
                    {
                        cover.Risks.Add(OssRiskCodes.EVAC);
                    }

                    if (options.Contains(OptionCodes.RENT))
                    {
                        cover.Risks.Add(OssRiskCodes.LSAVTO);
                    }

                    if (options.Contains(OptionCodes.TECHHELP))
                    {
                        cover.Risks.Add(OssRiskCodes.TECHHELP);
                    }

                    if (options.Contains(OptionCodes.AVARCOM2PAR)
                        || options.Contains(OptionCodes.AVARCOMACCIDENT)
                        || options.Contains(OptionCodes.AVARCOMANY)
                        || options.Contains(OptionCodes.AVARCOMNOTE))
                    {
                        cover.Risks.Add(OssRiskCodes.AVARKOM);
                    }
                }

                if (cover.Code == OssCoverCodes.AUTOKASKO && cover.Risks.Contains(OssRiskCodes.DMG) && cover.Risks.Contains(OssRiskCodes.DMGTOTAL))
                {
                    cover.Risks.Remove(OssRiskCodes.DMGTOTAL);
                }

                propertyDto.Add(cover);
            }
        }

        private string GetRestrictionValueForOffer(int? offerId)
        {
            const string defaultValue = "20000";

            if (offerId.HasValue)
            {
                _entitySettingsManager.TryGetSettingValue<Dictionary<int, string>>(KaskoCore.Code.Constants.EntitySettingCodes.FranchiseAutoKaskoOffersRestrictionValues, out var offersRestrictionValues);

                if (offersRestrictionValues.ContainsKey(offerId.Value))
                {
                    return offersRestrictionValues[offerId.Value];
                }
            }

            return defaultValue;
        }

        protected override void MapCoveragesToDeal(List<OssUniCoverDto> propertyDto, Deal deal)
        {
            if (propertyDto == null)
            {
                return;
            }

            foreach (var cover in propertyDto)
            {
                var restriction = cover.Restrictions?.FirstOrDefault(x => x.Type == CoverageOssType);

                var coverage = new DealCoverage
                {
                    ProductCoverage = new ProductCoverage
                    {
                        CoverageCode = MapHelper.MapForDictionaryValue(cover.Code, MapDictionarys.ProductCoverageCodeToOssCoverCodeMapping)
                    },
                    Sum = MapHelper.ConvertToDecimal(restriction?.Value),
                    ComponentCalculationResult = new ComponentCalculationResult
                    {
                        Value = cover.Premium
                    }
                };

                if (deal.DealConditionGroups.Count == 0)
                {
                    deal.DealConditionGroups.Add(new DealConditionGroup
                    {
                        InsuranceObjectConditions = new List<InsuranceObjectCondition> 
                        {
                            new InsuranceObjectCondition()
                        }
                    });
                }

                deal.DealConditionGroups[0].InsuranceObjectConditions[0].DealCoverages
                    .Add(coverage);
            }
        }

        private string KaskoDetermineCoverageSum(DealCoverage dealCoverage, CultureInfo ci)
        {
            var sum = DetermineCoverageSum(dealCoverage, ci);

            if (decimal.TryParse(sum, out var result)
                && result == decimal.Zero)
            {
                var coverageCode = dealCoverage.ProductCoverage.CoverageCode;
                sum = coverageCode switch
                {
                    CoverageCodes.CIVILLIABILITYAUTO => GetRiskSum(RiskCodes.CIVILLIABILITY),
                    CoverageCodes.AUTOKASKO => GetRiskSum(RiskCodes.DMGSECPART) ?? GetRiskSum(RiskCodes.DAMAGE),
                    CoverageCodes.DAMAGE => GetRiskSum(RiskCodes.DMGSECPART),
                    _ => sum
                };
            }

            return sum ?? "0";

            string GetRiskSum(string riskCode)
            {
                var risk = dealCoverage.DealRisks.SingleOrDefault(r => r.ProductRisk.RiskCode == riskCode);
                return risk?.Sum?.ToString(OssConstants.SumFormat, ci);
            }
        }
    }
}

Расскажи как происходит маппинг "DMG_SECPART" и что это такое вообще опция или риск или покрытие