package ru.yandex.direct.api.v5.entity.ads.converter;

import java.util.ArrayList;
import java.util.EnumSet;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.xml.bind.JAXBElement;

import com.yandex.direct.api.v5.ads.AdBuilderAdGetItem;
import com.yandex.direct.api.v5.ads.AdFieldEnum;
import com.yandex.direct.api.v5.ads.AdGetItem;
import com.yandex.direct.api.v5.ads.ContentPromotionCollectionAdFieldEnum;
import com.yandex.direct.api.v5.ads.ContentPromotionCollectionAdGet;
import com.yandex.direct.api.v5.ads.ContentPromotionEdaAdFieldEnum;
import com.yandex.direct.api.v5.ads.ContentPromotionEdaAdGet;
import com.yandex.direct.api.v5.ads.ContentPromotionServiceAdFieldEnum;
import com.yandex.direct.api.v5.ads.ContentPromotionServiceAdGet;
import com.yandex.direct.api.v5.ads.ContentPromotionVideoAdFieldEnum;
import com.yandex.direct.api.v5.ads.ContentPromotionVideoAdGet;
import com.yandex.direct.api.v5.ads.CpcVideoAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.CpcVideoAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.CpmBannerAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.CpmBannerAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.CpmVideoAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.CpmVideoAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.DynamicTextAdFieldEnum;
import com.yandex.direct.api.v5.ads.DynamicTextAdGet;
import com.yandex.direct.api.v5.ads.MobileAppAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.MobileAppAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.MobileAppAdFieldEnum;
import com.yandex.direct.api.v5.ads.MobileAppAdGet;
import com.yandex.direct.api.v5.ads.MobileAppCpcVideoAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.MobileAppCpcVideoAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.MobileAppImageAdFieldEnum;
import com.yandex.direct.api.v5.ads.MobileAppImageAdGet;
import com.yandex.direct.api.v5.ads.ObjectFactory;
import com.yandex.direct.api.v5.ads.PriceExtensionGetItem;
import com.yandex.direct.api.v5.ads.SmartAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.SmartAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.TextAdBuilderAdFieldEnum;
import com.yandex.direct.api.v5.ads.TextAdBuilderAdGet;
import com.yandex.direct.api.v5.ads.TextAdFieldEnum;
import com.yandex.direct.api.v5.ads.TextAdGet;
import com.yandex.direct.api.v5.ads.TextAdPriceExtensionFieldEnum;
import com.yandex.direct.api.v5.ads.TextImageAdFieldEnum;
import com.yandex.direct.api.v5.ads.TextImageAdGet;
import com.yandex.direct.api.v5.general.ExtensionModeration;
import com.yandex.direct.api.v5.general.StateEnum;
import com.yandex.direct.api.v5.general.StatusEnum;
import com.yandex.direct.api.v5.general.YesNoEnum;
import one.util.streamex.EntryStream;
import one.util.streamex.StreamEx;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import ru.yandex.direct.api.v5.common.EnumPropertyFilter;
import ru.yandex.direct.api.v5.entity.ads.StatusClarificationTranslations;
import ru.yandex.direct.api.v5.entity.ads.container.AdsGetContainer;
import ru.yandex.direct.api.v5.entity.ads.delegate.AdAnyFieldEnum;
import ru.yandex.direct.common.TranslationService;
import ru.yandex.direct.common.util.PropertyFilter;
import ru.yandex.direct.core.entity.adgroup.model.AdGroupType;
import ru.yandex.direct.core.entity.banner.model.BannerTurboLandingStatusModerate;
import ru.yandex.direct.core.entity.banner.model.BannerWithSystemFields;
import ru.yandex.direct.core.entity.banner.model.ContentPromotionBanner;
import ru.yandex.direct.core.entity.banner.model.CpcVideoBanner;
import ru.yandex.direct.core.entity.banner.model.CpmBanner;
import ru.yandex.direct.core.entity.banner.model.DynamicBanner;
import ru.yandex.direct.core.entity.banner.model.ImageBanner;
import ru.yandex.direct.core.entity.banner.model.MobileAppBanner;
import ru.yandex.direct.core.entity.banner.model.PerformanceBannerMain;
import ru.yandex.direct.core.entity.banner.model.TextBanner;
import ru.yandex.direct.core.entity.campaign.model.Campaign;
import ru.yandex.direct.core.entity.creative.model.Creative;
import ru.yandex.direct.core.entity.mobilecontent.model.MobileContent;

import static java.util.stream.Collectors.toCollection;
import static java.util.stream.Collectors.toList;
import static ru.yandex.direct.api.v5.entity.ads.converter.AdExtensionsConverter.convertAdExtensions;
import static ru.yandex.direct.api.v5.entity.ads.converter.AgeLabelConverter.convertAgeLabel;
import static ru.yandex.direct.api.v5.entity.ads.converter.CategoriesConverter.convertCategories;
import static ru.yandex.direct.api.v5.entity.ads.converter.MobileAppActionConverter.convertMobileAppAction;
import static ru.yandex.direct.api.v5.entity.ads.converter.MobileAppFeatureConverter.convertMobileAppFeatures;
import static ru.yandex.direct.api.v5.entity.ads.converter.ModerationStatusBuilder.buildAdImageModeration;
import static ru.yandex.direct.api.v5.entity.ads.converter.ModerationStatusBuilder.buildDisplayUrlPathModeration;
import static ru.yandex.direct.api.v5.entity.ads.converter.ModerationStatusBuilder.buildSitelinksModeration;
import static ru.yandex.direct.api.v5.entity.ads.converter.ModerationStatusBuilder.buildVCardModeration;
import static ru.yandex.direct.api.v5.entity.ads.converter.ModerationStatusBuilder.convertVideoExtension;
import static ru.yandex.direct.api.v5.entity.ads.converter.StateAndStatusCalculator.calcState;
import static ru.yandex.direct.api.v5.entity.ads.converter.StateAndStatusCalculator.calcStatus;
import static ru.yandex.direct.api.v5.entity.ads.converter.StateAndStatusCalculator.calcStatusClarification;
import static ru.yandex.direct.api.v5.entity.ads.converter.TrackingPixelsConverter.convertTrackingPixels;
import static ru.yandex.direct.api.v5.entity.ads.converter.TypeAndSubtypesConverter.calcSubtype;
import static ru.yandex.direct.api.v5.entity.ads.converter.TypeAndSubtypesConverter.convertType;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isContentPromotionBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isCpcVideoBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isCpmBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isDynamicBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isImageCreativeBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isImageHashBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isMobileAppBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isPerformanceBanner;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isPerformanceBannerMain;
import static ru.yandex.direct.core.entity.banner.service.validation.type.BannerTypeValidationPredicates.isTextBanner;
import static ru.yandex.direct.utils.FunctionalUtils.mapList;

@Component
@ParametersAreNonnullByDefault
public class GetResponseConverter {
    private static final ObjectFactory FACTORY = new ObjectFactory();

    private final EnumPropertyFilter<AdFieldEnum> baseAdPropertyFilter;
    private final EnumPropertyFilter<TextAdFieldEnum> textAdPropertyFilter;
    private final EnumPropertyFilter<TextAdPriceExtensionFieldEnum> textAdPriceExtensionPropertyFilter;
    private final EnumPropertyFilter<MobileAppAdFieldEnum> mobileAppAdPropertyFilter;
    private final EnumPropertyFilter<CpcVideoAdBuilderAdFieldEnum> cpcVideoAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<CpmVideoAdBuilderAdFieldEnum> cpmVideoAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<DynamicTextAdFieldEnum> dynamicTextAdPropertyFilter;
    private final EnumPropertyFilter<TextImageAdFieldEnum> textImageAdPropertyFilter;
    private final EnumPropertyFilter<MobileAppImageAdFieldEnum> mobileAppImageAdPropertyFilter;
    private final EnumPropertyFilter<MobileAppCpcVideoAdBuilderAdFieldEnum> mobileAppCpcVideoAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<TextAdBuilderAdFieldEnum> textAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<MobileAppAdBuilderAdFieldEnum> mobileAppAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<CpmBannerAdBuilderAdFieldEnum> cpmBannerAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<SmartAdBuilderAdFieldEnum> smartAdBuilderAdPropertyFilter;
    private final EnumPropertyFilter<ContentPromotionVideoAdFieldEnum> contentPromotionVideoAdPropertyFilter;
    private final EnumPropertyFilter<ContentPromotionCollectionAdFieldEnum> contentPromotionCollectionAdPropertyFilter;
    private final EnumPropertyFilter<ContentPromotionServiceAdFieldEnum> contentPromotionServiceAdPropertyFilter;
    private final EnumPropertyFilter<ContentPromotionEdaAdFieldEnum> contentPromotionEdaAdPropertyFilter;
    private final TranslationService translationService;
    private final ButtonExtensionConverter buttonExtensionConverter;
    private final LogoConverter logoConverter;

    @Autowired
    public GetResponseConverter(PropertyFilter propertyFilter,
                                TranslationService translationService,
                                ButtonExtensionConverter buttonExtensionConverter, LogoConverter logoConverter) {
        baseAdPropertyFilter = EnumPropertyFilter.from(AdFieldEnum.class, propertyFilter);
        textAdPropertyFilter = EnumPropertyFilter.from(TextAdFieldEnum.class, propertyFilter);
        textAdPriceExtensionPropertyFilter =
                EnumPropertyFilter.from(TextAdPriceExtensionFieldEnum.class, propertyFilter);
        mobileAppAdPropertyFilter = EnumPropertyFilter.from(MobileAppAdFieldEnum.class, propertyFilter);
        cpcVideoAdBuilderAdPropertyFilter =
                EnumPropertyFilter.from(CpcVideoAdBuilderAdFieldEnum.class, propertyFilter);
        cpmVideoAdBuilderAdPropertyFilter =
                EnumPropertyFilter.from(CpmVideoAdBuilderAdFieldEnum.class, propertyFilter);
        dynamicTextAdPropertyFilter = EnumPropertyFilter.from(DynamicTextAdFieldEnum.class, propertyFilter);
        textImageAdPropertyFilter = EnumPropertyFilter.from(TextImageAdFieldEnum.class, propertyFilter);
        mobileAppImageAdPropertyFilter = EnumPropertyFilter.from(MobileAppImageAdFieldEnum.class, propertyFilter);
        mobileAppCpcVideoAdBuilderAdPropertyFilter =
                EnumPropertyFilter.from(MobileAppCpcVideoAdBuilderAdFieldEnum.class, propertyFilter);
        textAdBuilderAdPropertyFilter = EnumPropertyFilter.from(TextAdBuilderAdFieldEnum.class, propertyFilter);
        mobileAppAdBuilderAdPropertyFilter =
                EnumPropertyFilter.from(MobileAppAdBuilderAdFieldEnum.class, propertyFilter);
        cpmBannerAdBuilderAdPropertyFilter =
                EnumPropertyFilter.from(CpmBannerAdBuilderAdFieldEnum.class, propertyFilter);
        smartAdBuilderAdPropertyFilter =
                EnumPropertyFilter.from(SmartAdBuilderAdFieldEnum.class, propertyFilter);
        contentPromotionVideoAdPropertyFilter = EnumPropertyFilter.from(ContentPromotionVideoAdFieldEnum.class,
                propertyFilter);
        contentPromotionCollectionAdPropertyFilter =
                EnumPropertyFilter.from(ContentPromotionCollectionAdFieldEnum.class,
                        propertyFilter);
        contentPromotionServiceAdPropertyFilter = EnumPropertyFilter.from(ContentPromotionServiceAdFieldEnum.class,
                propertyFilter);
        contentPromotionEdaAdPropertyFilter = EnumPropertyFilter.from(ContentPromotionEdaAdFieldEnum.class,
                propertyFilter);
        this.translationService = translationService;
        this.buttonExtensionConverter = buttonExtensionConverter;
        this.logoConverter = logoConverter;
    }

    TextImageAdGet convertTextImageBanner(ImageBanner ad) {
        return FACTORY.createTextImageAdGet()
                .withButtonExtension(
                        FACTORY.createTextImageAdGetButtonExtension(buttonExtensionConverter.convert(FACTORY, ad)))
                .withButtonExtensionModeration(FACTORY.createTextImageAdGetButtonExtensionModeration(buttonExtensionConverter.convertButtonExtensionStatusModerate(ad.getButtonStatusModerate(), translationService)))
                .withLogoExtensionHash(FACTORY.createTextImageAdGetLogoExtensionHash(ad.getLogoImageHash()))
                .withLogoExtensionModeration(FACTORY.createTextImageAdGetLogoExtensionModeration(
                        logoConverter.convertLogoStatusModerate(ad.getLogoStatusModerate(),
                                translationService)))
                .withTitle(FACTORY.createTextImageAdGetTitle(ad.getTitle()))
                .withTitle2(FACTORY.createTextImageAdGetTitle2(ad.getTitleExtension()))
                .withText(FACTORY.createTextImageAdGetText(ad.getBody()))
                .withTurboPageId(FACTORY.createTextImageAdGetTurboPageId(ad.getTurboLandingId()))
                .withTurboPageModeration(FACTORY.createTextImageAdGetTurboPageModeration(
                        convertBannerTurbolandingStatusModerate(
                                ad.getTurboLandingStatusModerate(), translationService)))
                .withHref(FACTORY.createTextImageAdGetHref(ad.getHref()))
                .withAdImageHash(ad.getImageHash());
    }

    static MobileAppImageAdGet convertMobileAppImageBanner(ImageBanner ad) {
        return FACTORY.createMobileAppImageAdGet()
                .withTrackingUrl(FACTORY.createMobileAppImageAdGetTrackingUrl(ad.getHref()))
                .withAdImageHash(ad.getImageHash());
    }

    static MobileAppCpcVideoAdBuilderAdGet convertMobileAppCpcVideoBanner(AdsGetContainer adsGetContainer) {
        CpcVideoBanner ad = (CpcVideoBanner) adsGetContainer.getAd();
        Creative creative = adsGetContainer.getCreative();

        return FACTORY.createMobileAppCpcVideoAdBuilderAdGet()
                .withTrackingUrl(FACTORY.createMobileAppCpcVideoAdBuilderAdGetTrackingUrl(ad.getHref()))
                .withCreative(convertAdBuilderCreative(creative));
    }

    static AdBuilderAdGetItem convertAdBuilderCreative(@Nullable Creative creative) {
        AdBuilderAdGetItem adBuilderAdGetItem = FACTORY.createAdBuilderAdGetItem();

        if (creative != null) {
            adBuilderAdGetItem
                    .withCreativeId(creative.getId())
                    .withPreviewUrl(creative.getLivePreviewUrl())
                    .withThumbnailUrl(creative.getPreviewUrl());
        }

        return adBuilderAdGetItem;
    }

    TextAdBuilderAdGet convertTextAdBuilderBanner(AdsGetContainer adsGetContainer) {
        ImageBanner ad = (ImageBanner) adsGetContainer.getAd();
        Creative creative = adsGetContainer.getCreative();

        return FACTORY.createTextAdBuilderAdGet()
                .withButtonExtension(
                        FACTORY.createTextAdBuilderAdGetButtonExtension(buttonExtensionConverter.convert(FACTORY,
                                ad)))
                .withButtonExtensionModeration(FACTORY.createTextAdBuilderAdGetButtonExtensionModeration(buttonExtensionConverter.convertButtonExtensionStatusModerate(ad.getButtonStatusModerate(), translationService)))
                .withLogoExtensionHash(FACTORY.createTextAdBuilderAdGetLogoExtensionHash(ad.getLogoImageHash()))
                .withLogoExtensionModeration(FACTORY.createTextImageAdGetLogoExtensionModeration(
                        logoConverter.convertLogoStatusModerate(ad.getLogoStatusModerate(),
                                translationService)))
                .withTitle(FACTORY.createTextAdBuilderAdGetTitle(ad.getTitle()))
                .withTitle2(FACTORY.createTextAdBuilderAdGetTitle2(ad.getTitleExtension()))
                .withText(FACTORY.createTextAdBuilderAdGetText(ad.getBody()))
                .withTurboPageId(FACTORY.createTextAdBuilderAdGetTurboPageId(ad.getTurboLandingId()))
                .withTurboPageModeration(FACTORY.createTextAdBuilderAdGetTurboPageModeration(
                        convertBannerTurbolandingStatusModerate(
                                ad.getTurboLandingStatusModerate(), translationService)))
                .withCreative(convertAdBuilderCreative(creative))
                .withHref(FACTORY.createTextAdBuilderAdGetHref(ad.getHref()));
    }

    static MobileAppAdBuilderAdGet convertMobileAppAdBuilderBanner(AdsGetContainer adsGetContainer) {
        ImageBanner ad = (ImageBanner) adsGetContainer.getAd();
        Creative creative = adsGetContainer.getCreative();

        return FACTORY.createMobileAppAdBuilderAdGet()
                .withCreative(convertAdBuilderCreative(creative))
                .withTrackingUrl(FACTORY.createMobileAppAdBuilderAdGetTrackingUrl(ad.getHref()));
    }

    private CpmBannerAdBuilderAdGet convertCpmBanner(AdsGetContainer adsGetContainer) {
        CpmBanner ad = (CpmBanner) adsGetContainer.getAd();
        Creative creative = adsGetContainer.getCreative();

        return FACTORY.createCpmBannerAdBuilderAdGet()
                .withTurboPageId(FACTORY.createCpmBannerAdBuilderAdGetTurboPageId(ad.getTurboLandingId()))
                .withTurboPageModeration(FACTORY.createCpmBannerAdBuilderAdGetTurboPageModeration(
                        convertBannerTurbolandingStatusModerate(
                                ad.getTurboLandingStatusModerate(), translationService)))
                .withCreative(convertAdBuilderCreative(creative))
                .withHref(FACTORY.createCpmBannerAdBuilderAdGetHref(ad.getHref()))
                .withTrackingPixels(FACTORY.createCpmBannerAdBuilderAdGetTrackingPixels(
                        convertTrackingPixels(ad.getPixels())))
                .withTnsId(FACTORY.createCpmBannerAdBuilderAdGetTnsId(ad.getTnsId()));
    }

    MobileAppAdGet convertMobileAppBanner(AdsGetContainer adsGetContainer) {
        MobileAppBanner ad = (MobileAppBanner) adsGetContainer.getAd();

        MobileContent mobileContent = adsGetContainer.getMobileContent();

        return FACTORY.createMobileAppAdGet()
                .withTitle(ad.getTitle())
                .withText(ad.getBody())
                .withTrackingUrl(FACTORY.createMobileAppAdBaseTrackingUrl(ad.getHref()))
                .withImpressionUrl(FACTORY.createMobileAppAdBaseImpressionUrl(ad.getImpressionUrl()))
                .withAction(convertMobileAppAction(ad.getPrimaryAction()))
                .withAdImageHash(FACTORY.createMobileAppAdBaseAdImageHash(ad.getImageHash()))
                .withAdImageModeration(FACTORY.createMobileAppAdGetAdImageModeration(
                        buildAdImageModeration(ad, adsGetContainer.getImageModerationReasons(), translationService)))
                .withFeatures(convertMobileAppFeatures(ad.getReflectedAttributes(), mobileContent))
                .withVideoExtension(
                        convertVideoExtension(adsGetContainer.getBannerCreative(), adsGetContainer.getCreative()));
    }

    private CpcVideoAdBuilderAdGet convertCpcVideoBanner(AdsGetContainer adsGetContainer) {
        CpcVideoBanner ad = (CpcVideoBanner) adsGetContainer.getAd();
        Creative creative = adsGetContainer.getCreative();

        return FACTORY.createCpcVideoAdBuilderAdGet()
                .withTurboPageId(FACTORY.createCpcVideoAdBuilderAdGetTurboPageId(ad.getTurboLandingId()))
                .withTurboPageModeration(FACTORY.createCpcVideoAdBuilderAdGetTurboPageModeration(
                        convertBannerTurbolandingStatusModerate(
                                ad.getTurboLandingStatusModerate(), translationService)))
                .withHref(FACTORY.createCpcVideoAdBuilderAdGetHref(ad.getHref()))
                .withCreative(convertAdBuilderCreative(creative));
    }

    private CpmVideoAdBuilderAdGet convertCpmVideoBanner(AdsGetContainer adsGetContainer) {
        CpmBanner ad = (CpmBanner) adsGetContainer.getAd();
        Creative creative = adsGetContainer.getCreative();

        return FACTORY.createCpmVideoAdBuilderAdGet()
                .withButtonExtension(
                        FACTORY.createCpmVideoAdBuilderAdGetButtonExtension(buttonExtensionConverter.convert(FACTORY,
                                ad)))
                .withButtonExtensionModeration(FACTORY.createCpmVideoAdBuilderAdGetButtonExtensionModeration(buttonExtensionConverter.convertButtonExtensionStatusModerate(ad.getButtonStatusModerate(), translationService)))
                .withLogoExtensionHash(FACTORY.createCpmVideoAdBuilderAdGetLogoExtensionHash(ad.getLogoImageHash()))
                .withLogoExtensionModeration(FACTORY.createTextImageAdGetLogoExtensionModeration(logoConverter.convertLogoStatusModerate(ad.getLogoStatusModerate(), translationService)))
                .withTitle(FACTORY.createCpmVideoAdBuilderAdGetTitle(ad.getTitle()))
                .withTitle2(FACTORY.createCpmVideoAdBuilderAdGetTitle2(ad.getTitleExtension()))
                .withText(FACTORY.createCpmVideoAdBuilderAdGetText(ad.getBody()))
                .withTurboPageId(FACTORY.createCpmBannerAdBuilderAdGetTurboPageId(ad.getTurboLandingId()))
                .withTurboPageModeration(FACTORY.createCpmBannerAdBuilderAdGetTurboPageModeration(
                        convertBannerTurbolandingStatusModerate(
                                ad.getTurboLandingStatusModerate(), translationService)))
                .withCreative(convertAdBuilderCreative(creative))
                .withHref(FACTORY.createCpmBannerAdBuilderAdGetHref(ad.getHref()))
                .withTrackingPixels(FACTORY.createCpmBannerAdBuilderAdGetTrackingPixels(
                        convertTrackingPixels(ad.getPixels())))
                .withTnsId(FACTORY.createCpmBannerAdBuilderAdGetTnsId(ad.getTnsId()));
    }

    private static ContentPromotionCollectionAdGet convertContentPromotionCollection(AdsGetContainer adsGetContainer) {
        ContentPromotionBanner ad = (ContentPromotionBanner) adsGetContainer.getAd();

        return FACTORY.createContentPromotionCollectionAdGet()
                .withPromotedContentId(ad.getContentPromotionId())
                .withVisitHref(FACTORY.createContentPromotionCollectionAdGetVisitHref(ad.getVisitUrl()));
    }

    private static ContentPromotionVideoAdGet convertContentPromotionVideo(AdsGetContainer adsGetContainer) {
        ContentPromotionBanner ad = (ContentPromotionBanner) adsGetContainer.getAd();

        return FACTORY.createContentPromotionVideoAdGet()
                .withPromotedContentId(ad.getContentPromotionId())
                .withVisitHref(FACTORY.createContentPromotionVideoAdGetVisitHref(ad.getVisitUrl()))
                .withText(ad.getBody())
                .withTitle(ad.getTitle());
    }

    private static ContentPromotionServiceAdGet convertContentPromotionService(AdsGetContainer adsGetContainer) {
        ContentPromotionBanner ad = (ContentPromotionBanner) adsGetContainer.getAd();

        return FACTORY.createContentPromotionServiceAdGet()
                .withPromotedContentId(ad.getContentPromotionId())
                .withTitle(ad.getTitle());
    }

    private static ContentPromotionEdaAdGet convertContentPromotionEda(AdsGetContainer adsGetContainer) {
        ContentPromotionBanner ad = (ContentPromotionBanner) adsGetContainer.getAd();

        return FACTORY.createContentPromotionEdaAdGet()
                .withPromotedContentId(ad.getContentPromotionId())
                .withText(FACTORY.createContentPromotionEdaAdGetText(ad.getBody()))
                .withTitle(ad.getTitle());
    }

    @Nonnull
    private static JAXBElement<PriceExtensionGetItem> convertPriceExtension(@Nonnull TextBanner ad) {
        var price = ad.getBannerPrice();
        PriceExtensionGetItem item = BannerPriceConverter.fromCore(price);
        return FACTORY.createTextAdGetPriceExtension(item);
    }


    TextAdGet convertTextBanner(AdsGetContainer adsGetContainer) {
        TextBanner ad = (TextBanner) adsGetContainer.getAd();

        return FACTORY.createTextAdGet()
                .withButtonExtension(FACTORY.createTextAdGetButtonExtension(buttonExtensionConverter.convert(FACTORY,
                        ad)))
                .withButtonExtensionModeration(FACTORY.createTextAdGetButtonExtensionModeration(buttonExtensionConverter.convertButtonExtensionStatusModerate(ad.getButtonStatusModerate(), translationService)))
                .withLogoExtensionHash(FACTORY.createTextAdGetLogoExtensionHash(ad.getLogoImageHash()))
                .withLogoExtensionModeration(FACTORY.createTextImageAdGetLogoExtensionModeration(
                        logoConverter.convertLogoStatusModerate(ad.getLogoStatusModerate(),
                                translationService)))
                .withTitle(ad.getTitle())
                .withTurboPageId(FACTORY.createTextAdGetTurboPageId(ad.getTurboLandingId()))
                .withTurboPageModeration(FACTORY.createTextAdGetTurboPageModeration(
                        convertBannerTurbolandingStatusModerate(
                                ad.getTurboLandingStatusModerate(),
                                translationService)))
                .withTitle2(FACTORY.createTextAdGetTitle2(ad.getTitleExtension()))
                .withText(ad.getBody())
                .withHref(FACTORY.createTextAdGetHref(ad.getHref()))
                .withMobile(ad.getIsMobile() ? YesNoEnum.YES : YesNoEnum.NO)
                .withDisplayDomain(FACTORY.createTextAdGetDisplayDomain(ad.getDomain()))
                .withDisplayUrlPath(FACTORY.createTextAdGetDisplayUrlPath(ad.getDisplayHref()))
                .withDutPrefix(FACTORY.createTextAdGetDutPrefix(ad.getDisplayHrefPrefix()))
                .withDutSuffix(FACTORY.createTextAdGetDutSuffix(ad.getDisplayHrefSuffix()))
                .withVCardId(FACTORY.createTextAdGetBaseVCardId(ad.getVcardId()))
                .withAdImageHash(FACTORY.createTextAdGetBaseAdImageHash(ad.getImageHash()))
                .withSitelinkSetId(FACTORY.createTextAdGetBaseSitelinkSetId(ad.getSitelinksSetId()))
                .withAdExtensions(convertAdExtensions(ad.getCalloutIds()))
                .withAdImageModeration(FACTORY.createTextAdGetBaseAdImageModeration(
                        buildAdImageModeration(ad, adsGetContainer.getImageModerationReasons(), translationService)))
                .withDisplayUrlPathModeration(
                        buildDisplayUrlPathModeration(ad, adsGetContainer.getDisplayHrefModerationReasons(),
                                translationService))
                .withSitelinksModeration(buildSitelinksModeration(ad, adsGetContainer.getSitelinksModerationReasons(),
                        translationService))
                .withVCardModeration(
                        buildVCardModeration(ad, adsGetContainer.getVCardModerationReasons(), translationService))
                .withVideoExtension(
                        convertVideoExtension(adsGetContainer.getBannerCreative(), adsGetContainer.getCreative()))
                .withPriceExtension(convertPriceExtension(ad))
                .withBusinessId(FACTORY.createTextAdGetBusinessId(ad.getPermalinkId()))
                .withTrackingPhoneId(FACTORY.createTextAdGetTrackingPhoneId(ad.getPhoneId()))
                .withPreferVCardOverBusiness(FACTORY.createTextAdGetPreferVCardOverBusiness(
                        ad.getPreferVCardOverPermalink() != null && ad.getPreferVCardOverPermalink()
                                ? YesNoEnum.YES
                                : YesNoEnum.NO
                ))
                .withLfHref(FACTORY.createTextAdGetLfHref(ad.getLeadformHref()))
                .withLfButtonText(FACTORY.createTextAdGetLfButtonText(ad.getLeadformButtonText()));
    }

    DynamicTextAdGet convertDynamicBanner(AdsGetContainer adsGetContainer) {
        DynamicBanner ad = (DynamicBanner) adsGetContainer.getAd();

        return FACTORY.createDynamicTextAdGet()
                .withText(ad.getBody())
                .withVCardId(FACTORY.createTextAdGetBaseVCardId(ad.getVcardId()))
                .withAdImageHash(FACTORY.createTextAdGetBaseAdImageHash(ad.getImageHash()))
                .withSitelinkSetId(FACTORY.createTextAdGetBaseSitelinkSetId(ad.getSitelinksSetId()))
                .withAdExtensions(convertAdExtensions(ad.getCalloutIds()))
                .withVCardModeration(
                        buildVCardModeration(ad, adsGetContainer.getVCardModerationReasons(), translationService))
                .withSitelinksModeration(buildSitelinksModeration(ad, adsGetContainer.getSitelinksModerationReasons(),
                        translationService))
                .withAdImageModeration(FACTORY.createTextAdGetBaseAdImageModeration(
                        buildAdImageModeration(ad, adsGetContainer.getImageModerationReasons(), translationService)));
    }

    SmartAdBuilderAdGet convertSmartAdBuilderMainBanner(AdsGetContainer adsGetContainer) {
        PerformanceBannerMain ad = (PerformanceBannerMain) adsGetContainer.getAd();

        return FACTORY.createSmartAdBuilderAdGet()
                .withLogoExtensionHash(FACTORY.createSmartAdBuilderAdGetLogoExtensionHash(ad.getLogoImageHash()))
                .withLogoExtensionModeration(FACTORY.createSmartAdBuilderAdGetLogoExtensionModeration(
                        logoConverter.convertLogoStatusModerate(ad.getLogoStatusModerate(),
                                translationService)));
    }

    static SmartAdBuilderAdGet convertSmartAdBuilderBanner(AdsGetContainer adsGetContainer) {
        Creative creative = adsGetContainer.getCreative();
        return FACTORY.createSmartAdBuilderAdGet()
                .withCreative(convertAdBuilderCreative(creative));
    }

    private static ExtensionModeration convertBannerTurbolandingStatusModerate(
            BannerTurboLandingStatusModerate statusModerate, TranslationService translationService

    ) {
        if (statusModerate == null) {
            return null;
        }
        ExtensionModeration extensionModeration = new ExtensionModeration();
        StatusClarificationTranslations translations = StatusClarificationTranslations.INSTANCE;

        switch (statusModerate) {
            case YES:
                return extensionModeration
                        .withStatus(StatusEnum.ACCEPTED)
                        .withStatusClarification(translationService.translate(translations.adAccepted()));
            case NO:
                return extensionModeration
                        .withStatus(StatusEnum.REJECTED)
                        .withStatusClarification(translationService.translate(translations
                                .turboLandingRejectedAtModeration()));
            case SENT:
            case SENDING:
            case READY:
                return extensionModeration
                        .withStatus(StatusEnum.MODERATION)
                        .withStatusClarification(translationService.translate(translations.adAwaitingModeration()));
            case NEW:
                return extensionModeration
                        .withStatus(StatusEnum.DRAFT)
                        .withStatusClarification(translationService.translate(translations.relatedObjectIsDraft()));
            default:
                return extensionModeration.withStatus(StatusEnum.UNKNOWN);
        }
    }

    public AdGetItem convertResponseItem(AdsGetContainer adsGetContainer) {
        BannerWithSystemFields ad = adsGetContainer.getAd();

        Campaign campaign = adsGetContainer.getCampaign();

        StatusEnum status = calcStatus(ad);
        StateEnum state = calcState(ad, adsGetContainer.isStoppedByMonitoring(), campaign);

        AdGetItem adGetItem = FACTORY.createAdGetItem();
        boolean isCpmVideo = AdGroupType.CPM_VIDEO.equals(adsGetContainer.getAdGroupType());
        adGetItem
                .withId(ad.getId())
                .withAdGroupId(ad.getAdGroupId())
                .withCampaignId(ad.getCampaignId())
                .withStatus(status)
                .withState(state)
                .withStatusClarification(calcStatusClarification(status, state, campaign.getStatusShow(),
                        adsGetContainer, translationService))
                .withAdCategories(convertCategories(ad.getFlags()))
                .withAgeLabel(convertAgeLabel(ad.getFlags()))
                .withType(convertType(ad, adsGetContainer.getAdGroupType(),
                        adsGetContainer.getContentPromotionAdgroupType()))
                .withSubtype(calcSubtype(ad));

        if (isTextBanner(ad)) {
            adGetItem.withTextAd(convertTextBanner(adsGetContainer));
        } else if (isMobileAppBanner(ad)) {
            adGetItem.withMobileAppAd(convertMobileAppBanner(adsGetContainer));
        } else if (isDynamicBanner(ad)) {
            adGetItem.withDynamicTextAd(convertDynamicBanner(adsGetContainer));
        } else if (isCpcVideoBanner(ad)) {
            Boolean isMobileVideo = ((CpcVideoBanner) ad).getIsMobileVideo();
            if (isMobileVideo == null) {
                throw new IllegalArgumentException("can\'t build subtype structure for ad " + ad);
            } else if (isMobileVideo) {
                adGetItem.withMobileAppCpcVideoAdBuilderAd(convertMobileAppCpcVideoBanner(adsGetContainer));
            } else {
                adGetItem.withCpcVideoAdBuilderAd(convertCpcVideoBanner(adsGetContainer));
            }
        } else if (isCpmVideo) {
            adGetItem.withCpmVideoAdBuilderAd(convertCpmVideoBanner(adsGetContainer));
        } else if (isImageHashBanner(ad)) {
            Boolean subType = ((ImageBanner) ad).getIsMobileImage();
            if (subType == null) {
                throw new IllegalArgumentException("can\'t build subtype structure for ad " + ad);
            } else if (subType) {
                adGetItem.withMobileAppImageAd(convertMobileAppImageBanner((ImageBanner) ad));
            } else {
                adGetItem.withTextImageAd(convertTextImageBanner((ImageBanner) ad));
            }
        } else if (isImageCreativeBanner(ad)) {
            Boolean subType = ((ImageBanner) ad).getIsMobileImage();
            if (subType == null) {
                throw new IllegalArgumentException("can\'t build subtype structure for ad " + ad);
            } else if (subType) {
                adGetItem.withMobileAppAdBuilderAd(convertMobileAppAdBuilderBanner(adsGetContainer));
            } else {
                adGetItem.withTextAdBuilderAd(convertTextAdBuilderBanner(adsGetContainer));
            }
        } else if (isCpmBanner(ad)) {
            adGetItem.withCpmBannerAdBuilderAd(convertCpmBanner(adsGetContainer));
        } else if (isPerformanceBanner(ad)) {
            adGetItem.withSmartAdBuilderAd(convertSmartAdBuilderBanner(adsGetContainer));
        } else if (isPerformanceBannerMain(ad)) {
            adGetItem.withSmartAdBuilderAd(convertSmartAdBuilderMainBanner(adsGetContainer));
        } else if (isContentPromotionBanner(ad)) {
            switch (adsGetContainer.getContentPromotionAdgroupType()) {
                case VIDEO:
                    adGetItem.withContentPromotionVideoAd(convertContentPromotionVideo(adsGetContainer));
                    break;
                case COLLECTION:
                    adGetItem.withContentPromotionCollectionAd(convertContentPromotionCollection(adsGetContainer));
                    break;
                case SERVICE:
                    adGetItem.withContentPromotionServiceAd(convertContentPromotionService(adsGetContainer));
                    break;
                case EDA:
                    adGetItem.withContentPromotionEdaAd(convertContentPromotionEda(adsGetContainer));
                    break;
                default:
                    throw new IllegalArgumentException("Unknown contentpromotiontype for ad " + ad);
            }
        }

        return adGetItem;
    }

    public void filterProperties(List<AdGetItem> getItems, Set<AdAnyFieldEnum> requestedFields) {
        List<String> propertyNames = new ArrayList<>();

        Map<? extends Class<?>, List<AdAnyFieldEnum>> requestedFieldsByType =
                requestedFields.stream().collect(Collectors.groupingBy(AdAnyFieldEnum::getEnumClass));

        List<TextAdGet> textAdItems = getItemsOfType(getItems, AdGetItem::getTextAd);
        if (!textAdItems.isEmpty()) {
            List<PriceExtensionGetItem> priceItems =
                    getPriceExtensionItems(propertyNames, requestedFieldsByType, textAdItems);

            Class<TextAdFieldEnum> fieldClass = TextAdFieldEnum.class;
            EnumSet<TextAdFieldEnum> textAdFields = EnumSet.noneOf(fieldClass);
            if (requestedFieldsByType.containsKey(fieldClass)) {
                textAdFields = getRequestedFieldsByType(requestedFieldsByType.get(fieldClass), fieldClass);
                propertyNames.add("textAd");
            }
            textAdPropertyFilter.filterProperties(textAdItems, textAdFields);

            if (requestedFieldsByType.containsKey(TextAdPriceExtensionFieldEnum.class) && !priceItems.isEmpty()) {
                // Склейка полей баннеров с ценами
                EntryStream.zip(textAdItems, priceItems)
                        .forKeyValue(
                                (ad, price) -> ad.withPriceExtension(FACTORY.createTextAdGetPriceExtension(price))
                        );
            }
        }

        List<MobileAppAdGet> mobileAppAdItems = getItemsOfType(getItems, AdGetItem::getMobileAppAd);
        if (!mobileAppAdItems.isEmpty()) {
            EnumSet<MobileAppAdFieldEnum> mobileAppAdFields = EnumSet.noneOf(MobileAppAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(MobileAppAdFieldEnum.class)) {
                mobileAppAdFields = getRequestedFieldsByType(requestedFieldsByType.get(MobileAppAdFieldEnum.class),
                        MobileAppAdFieldEnum.class);
                propertyNames.add("mobileAppAd");
            }

            mobileAppAdPropertyFilter.filterProperties(mobileAppAdItems, mobileAppAdFields);
        }

        List<CpcVideoAdBuilderAdGet> cpcVideoAdBuilderAdItems =
                getItemsOfType(getItems, AdGetItem::getCpcVideoAdBuilderAd);
        if (!cpcVideoAdBuilderAdItems.isEmpty()) {
            EnumSet<CpcVideoAdBuilderAdFieldEnum> cpcVideoAdBuilderAdFields =
                    EnumSet.noneOf(CpcVideoAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(CpcVideoAdBuilderAdFieldEnum.class)) {
                cpcVideoAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(CpcVideoAdBuilderAdFieldEnum.class),
                                CpcVideoAdBuilderAdFieldEnum.class);
                propertyNames.add("cpcVideoAdBuilderAd");
            }

            cpcVideoAdBuilderAdPropertyFilter.filterProperties(cpcVideoAdBuilderAdItems, cpcVideoAdBuilderAdFields);
        }

        List<CpmVideoAdBuilderAdGet> cpmVideoAdBuilderAdItems =
                getItemsOfType(getItems, AdGetItem::getCpmVideoAdBuilderAd);
        if (!cpmVideoAdBuilderAdItems.isEmpty()) {
            EnumSet<CpmVideoAdBuilderAdFieldEnum> cpmVideoAdBuilderAdFields =
                    EnumSet.noneOf(CpmVideoAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(CpmVideoAdBuilderAdFieldEnum.class)) {
                cpmVideoAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(CpmVideoAdBuilderAdFieldEnum.class),
                                CpmVideoAdBuilderAdFieldEnum.class);
                propertyNames.add("cpmVideoAdBuilderAd");
            }

            cpmVideoAdBuilderAdPropertyFilter.filterProperties(cpmVideoAdBuilderAdItems, cpmVideoAdBuilderAdFields);
        }

        List<DynamicTextAdGet> dynamicTextAdItems = getItemsOfType(getItems, AdGetItem::getDynamicTextAd);
        if (!dynamicTextAdItems.isEmpty()) {
            EnumSet<DynamicTextAdFieldEnum> dynamicTextAdFields = EnumSet.noneOf(DynamicTextAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(DynamicTextAdFieldEnum.class)) {
                dynamicTextAdFields = getRequestedFieldsByType(requestedFieldsByType.get(DynamicTextAdFieldEnum.class),
                        DynamicTextAdFieldEnum.class);
                propertyNames.add("dynamicTextAd");
            }

            dynamicTextAdPropertyFilter.filterProperties(dynamicTextAdItems, dynamicTextAdFields);
        }

        List<TextImageAdGet> textImageAdItems = getItemsOfType(getItems, AdGetItem::getTextImageAd);
        if (!textImageAdItems.isEmpty()) {
            EnumSet<TextImageAdFieldEnum> textImageAdFields = EnumSet.noneOf(TextImageAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(TextImageAdFieldEnum.class)) {
                textImageAdFields = getRequestedFieldsByType(requestedFieldsByType.get(TextImageAdFieldEnum.class),
                        TextImageAdFieldEnum.class);
                propertyNames.add("textImageAd");
            }

            textImageAdPropertyFilter.filterProperties(textImageAdItems, textImageAdFields);
        }

        List<MobileAppImageAdGet> mobileAppImageAdItems = getItemsOfType(getItems, AdGetItem::getMobileAppImageAd);
        if (!mobileAppImageAdItems.isEmpty()) {
            EnumSet<MobileAppImageAdFieldEnum> mobileAppImageAdFields = EnumSet.noneOf(MobileAppImageAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(MobileAppImageAdFieldEnum.class)) {
                mobileAppImageAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(MobileAppImageAdFieldEnum.class),
                                MobileAppImageAdFieldEnum.class);
                propertyNames.add("mobileAppImageAd");
            }

            mobileAppImageAdPropertyFilter.filterProperties(mobileAppImageAdItems, mobileAppImageAdFields);
        }

        List<MobileAppCpcVideoAdBuilderAdGet> mobileAppCpcVideoAdBuilderAdItems =
                getItemsOfType(getItems, AdGetItem::getMobileAppCpcVideoAdBuilderAd);
        if (!mobileAppCpcVideoAdBuilderAdItems.isEmpty()) {
            EnumSet<MobileAppCpcVideoAdBuilderAdFieldEnum> mobileAppCpcVideoAdBuilderAdFields =
                    EnumSet.noneOf(MobileAppCpcVideoAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(MobileAppCpcVideoAdBuilderAdFieldEnum.class)) {
                mobileAppCpcVideoAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(MobileAppCpcVideoAdBuilderAdFieldEnum.class),
                                MobileAppCpcVideoAdBuilderAdFieldEnum.class);
                propertyNames.add("mobileAppCpcVideoAdBuilderAd");
            }

            mobileAppCpcVideoAdBuilderAdPropertyFilter
                    .filterProperties(mobileAppCpcVideoAdBuilderAdItems, mobileAppCpcVideoAdBuilderAdFields);
        }

        List<TextAdBuilderAdGet> textAdBuilderAdItems = getItemsOfType(getItems, AdGetItem::getTextAdBuilderAd);
        if (!textAdBuilderAdItems.isEmpty()) {
            EnumSet<TextAdBuilderAdFieldEnum> textAdBuilderAdFields = EnumSet.noneOf(TextAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(TextAdBuilderAdFieldEnum.class)) {
                textAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(TextAdBuilderAdFieldEnum.class),
                                TextAdBuilderAdFieldEnum.class);
                propertyNames.add("textAdBuilderAd");
            }

            textAdBuilderAdPropertyFilter.filterProperties(textAdBuilderAdItems, textAdBuilderAdFields);
        }

        List<MobileAppAdBuilderAdGet> mobileAppAdBuilderAdItems =
                getItemsOfType(getItems, AdGetItem::getMobileAppAdBuilderAd);
        if (!mobileAppAdBuilderAdItems.isEmpty()) {
            EnumSet<MobileAppAdBuilderAdFieldEnum> mobileAppAdBuilderAdFields =
                    EnumSet.noneOf(MobileAppAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(MobileAppAdBuilderAdFieldEnum.class)) {
                mobileAppAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(MobileAppAdBuilderAdFieldEnum.class),
                                MobileAppAdBuilderAdFieldEnum.class);
                propertyNames.add("mobileAppAdBuilderAd");
            }

            mobileAppAdBuilderAdPropertyFilter.filterProperties(mobileAppAdBuilderAdItems, mobileAppAdBuilderAdFields);
        }

        List<CpmBannerAdBuilderAdGet> cpmBannerAdBuilderAdItems =
                getItemsOfType(getItems, AdGetItem::getCpmBannerAdBuilderAd);
        if (!cpmBannerAdBuilderAdItems.isEmpty()) {
            EnumSet<CpmBannerAdBuilderAdFieldEnum> cpmBannerAdBuilderAdFields =
                    EnumSet.noneOf(CpmBannerAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(CpmBannerAdBuilderAdFieldEnum.class)) {
                cpmBannerAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(CpmBannerAdBuilderAdFieldEnum.class),
                                CpmBannerAdBuilderAdFieldEnum.class);
                propertyNames.add("cpmBannerAdBuilderAd");
            }

            cpmBannerAdBuilderAdPropertyFilter.filterProperties(cpmBannerAdBuilderAdItems, cpmBannerAdBuilderAdFields);
        }

        List<SmartAdBuilderAdGet> smartAdBuilderAdItems = getItemsOfType(getItems, AdGetItem::getSmartAdBuilderAd);
        if (!smartAdBuilderAdItems.isEmpty()) {
            EnumSet<SmartAdBuilderAdFieldEnum> smartAdBuilderAdFields = EnumSet.noneOf(SmartAdBuilderAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(SmartAdBuilderAdFieldEnum.class)) {
                smartAdBuilderAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(SmartAdBuilderAdFieldEnum.class),
                                SmartAdBuilderAdFieldEnum.class);
                propertyNames.add("smartAdBuilderAd");
            }

            smartAdBuilderAdPropertyFilter.filterProperties(smartAdBuilderAdItems, smartAdBuilderAdFields);
        }

        List<ContentPromotionVideoAdGet> contentPromotionVideoAdItems =
                getItemsOfType(getItems, AdGetItem::getContentPromotionVideoAd);
        if (!contentPromotionVideoAdItems.isEmpty()) {
            EnumSet<ContentPromotionVideoAdFieldEnum> contentPromotionVideoAdFields =
                    EnumSet.noneOf(ContentPromotionVideoAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(ContentPromotionVideoAdFieldEnum.class)) {
                contentPromotionVideoAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(ContentPromotionVideoAdFieldEnum.class),
                                ContentPromotionVideoAdFieldEnum.class);
                propertyNames.add("contentPromotionVideoAd");
            }

            contentPromotionVideoAdPropertyFilter
                    .filterProperties(contentPromotionVideoAdItems, contentPromotionVideoAdFields);
        }

        List<ContentPromotionCollectionAdGet> contentPromotionCollectionAdItems =
                getItemsOfType(getItems, AdGetItem::getContentPromotionCollectionAd);
        if (!contentPromotionCollectionAdItems.isEmpty()) {
            EnumSet<ContentPromotionCollectionAdFieldEnum> contentPromotionCollectionAdFields =
                    EnumSet.noneOf(ContentPromotionCollectionAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(ContentPromotionCollectionAdFieldEnum.class)) {
                contentPromotionCollectionAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(ContentPromotionCollectionAdFieldEnum.class),
                                ContentPromotionCollectionAdFieldEnum.class);
                propertyNames.add("contentPromotionCollectionAd");
            }

            contentPromotionCollectionAdPropertyFilter
                    .filterProperties(contentPromotionCollectionAdItems, contentPromotionCollectionAdFields);
        }

        List<ContentPromotionServiceAdGet> contentPromotionServiceAdItems =
                getItemsOfType(getItems, AdGetItem::getContentPromotionServiceAd);
        if (!contentPromotionServiceAdItems.isEmpty()) {
            EnumSet<ContentPromotionServiceAdFieldEnum> contentPromotionServiceAdFields =
                    EnumSet.noneOf(ContentPromotionServiceAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(ContentPromotionServiceAdFieldEnum.class)) {
                contentPromotionServiceAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(ContentPromotionServiceAdFieldEnum.class),
                                ContentPromotionServiceAdFieldEnum.class);
                propertyNames.add("contentPromotionServiceAd");
            }

            contentPromotionServiceAdPropertyFilter
                    .filterProperties(contentPromotionServiceAdItems, contentPromotionServiceAdFields);
        }

        List<ContentPromotionEdaAdGet> contentPromotionEdaAdItems =
                getItemsOfType(getItems, AdGetItem::getContentPromotionEdaAd);
        if (!contentPromotionEdaAdItems.isEmpty()) {
            EnumSet<ContentPromotionEdaAdFieldEnum> contentPromotionEdaAdFields =
                    EnumSet.noneOf(ContentPromotionEdaAdFieldEnum.class);

            if (requestedFieldsByType.containsKey(ContentPromotionEdaAdFieldEnum.class)) {
                contentPromotionEdaAdFields =
                        getRequestedFieldsByType(requestedFieldsByType.get(ContentPromotionEdaAdFieldEnum.class),
                                ContentPromotionEdaAdFieldEnum.class);
                propertyNames.add("contentPromotionEdaAd");
            }

            contentPromotionEdaAdPropertyFilter
                    .filterProperties(contentPromotionEdaAdItems, contentPromotionEdaAdFields);
        }

        EnumSet<AdFieldEnum> baseAdFields = EnumSet.noneOf(AdFieldEnum.class);
        if (requestedFieldsByType.containsKey(AdFieldEnum.class)) {
            baseAdFields = getRequestedFieldsByType(requestedFieldsByType.get(AdFieldEnum.class), AdFieldEnum.class);
        }
        propertyNames.addAll(mapList(baseAdFields, baseAdPropertyFilter.getEnumToFieldMap()::get));
        baseAdPropertyFilter.filterPropertiesByNames(getItems, propertyNames);
    }

    /**
     * Выбирает из баннеров поля с ценами и фильтрует те, которые требуется вернуть в ответе.
     * Если цены нет - вернется null на весь блок
     *
     * @param propertyNames         Имена полей, которые вернутся в ответе
     * @param requestedFieldsByType Поля, которые нужно вернуть в ответе
     * @param textAdItems           Баннеры
     */
    private List<PriceExtensionGetItem> getPriceExtensionItems(List<String> propertyNames,
                                                               Map<? extends Class<?>, List<AdAnyFieldEnum>>
                                                                       requestedFieldsByType, List<TextAdGet>
                                                                       textAdItems) {
        Class<TextAdPriceExtensionFieldEnum> fieldClass = TextAdPriceExtensionFieldEnum.class;
        List<PriceExtensionGetItem> priceItems = mapList(textAdItems, ad -> ad.getPriceExtension().getValue());

        EnumSet<TextAdPriceExtensionFieldEnum> priceExtensionFields = EnumSet.noneOf(fieldClass);
        if (requestedFieldsByType.containsKey(fieldClass)) {
            priceExtensionFields = getRequestedFieldsByType(requestedFieldsByType.get(fieldClass), fieldClass);
            propertyNames.add("textAdPriceExtension");
        }

        textAdPriceExtensionPropertyFilter.filterProperties(StreamEx.of(priceItems).nonNull().toList(),
                priceExtensionFields);
        return priceItems;
    }

    private <T, R> List<R> getItemsOfType(List<T> items, Function<T, R> getter) {
        return items.stream().map(getter).filter(Objects::nonNull).collect(toList());
    }

    private <T extends Enum<T>> EnumSet<T> getRequestedFieldsByType(List<AdAnyFieldEnum> adAnyFieldEnums,
                                                                    Class<T> clazz) {
        return adAnyFieldEnums.stream().map(e -> clazz.cast(e.getValue()))
                .collect(toCollection(() -> EnumSet.noneOf(clazz)));
    }
}
