package ru.yandex.qe.dispenser.domain.dictionaries.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.inject.Inject;

import org.jetbrains.annotations.NotNull;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import ru.yandex.qe.dispenser.api.v1.DiAmount;
import ru.yandex.qe.dispenser.domain.Campaign;
import ru.yandex.qe.dispenser.domain.CampaignResource;
import ru.yandex.qe.dispenser.domain.CampaignServiceResourcesPreset;
import ru.yandex.qe.dispenser.domain.Resource;
import ru.yandex.qe.dispenser.domain.ResourceSegmentation;
import ru.yandex.qe.dispenser.domain.ResourceUnit;
import ru.yandex.qe.dispenser.domain.Segment;
import ru.yandex.qe.dispenser.domain.Segmentation;
import ru.yandex.qe.dispenser.domain.Service;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignDao;
import ru.yandex.qe.dispenser.domain.dao.campaign.CampaignResourceDao;
import ru.yandex.qe.dispenser.domain.dao.resource.unit.ResourceUnitDao;
import ru.yandex.qe.dispenser.domain.dao.service.resource.preset.CampaignServiceResourcesPresetDao;
import ru.yandex.qe.dispenser.domain.dictionaries.model.CampaignProvidersSettingsDictionary;
import ru.yandex.qe.dispenser.domain.hierarchy.Hierarchy;
import ru.yandex.qe.dispenser.domain.hierarchy.HierarchySupplier;
import ru.yandex.qe.dispenser.domain.index.LongIndexBase;

@Component
public class PerCampaignFrontDictionariesManager {

    @NotNull
    private final CampaignResourceDao campaignResourceDao;
    @NotNull
    private final CampaignDao campaignDao;
    @NotNull
    private final HierarchySupplier hierarchySupplier;
    @NotNull
    private final ResourceUnitDao resourceUnitDao;
    @NotNull
    private final CampaignServiceResourcesPresetDao presetDao;

    @Inject
    public PerCampaignFrontDictionariesManager(@NotNull final CampaignResourceDao campaignResourceDao,
                                               @NotNull final CampaignDao campaignDao,
                                               @NotNull final HierarchySupplier hierarchySupplier,
                                               @NotNull final ResourceUnitDao resourceUnitDao,
                                               @NotNull final CampaignServiceResourcesPresetDao presetDao) {
        this.campaignResourceDao = campaignResourceDao;
        this.campaignDao = campaignDao;
        this.hierarchySupplier = hierarchySupplier;
        this.resourceUnitDao = resourceUnitDao;
        this.presetDao = presetDao;
    }

    @NotNull
    @Transactional(propagation = Propagation.REQUIRED)
    public Optional<CampaignProvidersSettingsDictionary> getPerCampaignProviderSettings(final long campaignId) {
        final Optional<Campaign> campaignO = campaignDao.readOptional(campaignId);
        return campaignO.map(this::getPerCampaignProviderSettings);
    }

    @NotNull
    @Transactional(propagation = Propagation.REQUIRED)
    public CampaignProvidersSettingsDictionary getPerCampaignProviderSettings(@NotNull final Campaign campaign) {
        final CommonDictionaryParameters commonParameters = prepareCommonParameters(campaign);
        final List<CampaignProvidersSettingsDictionary.Segmentation> segmentationsDictionary
                = prepareSegmentationsDictionary(commonParameters);
        final List<CampaignProvidersSettingsDictionary.Provider> providersDictionary
                = prepareProvidersDictionary(campaign, commonParameters);
        return new CampaignProvidersSettingsDictionary(campaign.toView(), segmentationsDictionary, providersDictionary);
    }

    @NotNull
    private CommonDictionaryParameters prepareCommonParameters(@NotNull final Campaign campaign) {
        final Hierarchy hierarchy = hierarchySupplier.get();
        // All resources available in campaign
        final List<CampaignResource> campaignResources = campaignResourceDao.getByCampaignId(campaign.getId());
        final Set<Long> resourceIds = campaignResources.stream()
                .map(CampaignResource::getResourceId).collect(Collectors.toSet());
        // Missing resources are ignored, it's more robust this way
        final Map<Long, Resource> resourcesById = hierarchy.getResourceReader().tryGetByIds(resourceIds);
        // Segmentations for the available resources
        final Set<ResourceSegmentation> resourceSegmentations = hierarchy.getResourceSegmentationReader()
                .getResourceSegmentations(resourcesById.values());
        final Map<Long, Segmentation> segmentationsById = resourceSegmentations.stream()
                .map(ResourceSegmentation::getSegmentation).distinct()
                .collect(Collectors.toMap(LongIndexBase::getId, Function.identity()));
        final Set<Long> segmentationIds = segmentationsById.keySet();
        final Map<Long, Set<Segment>> segmentsBySegmentationId = hierarchy.getSegmentReader()
                .getBySegmentationIds(segmentationIds);
        return new CommonDictionaryParameters(segmentsBySegmentationId, segmentationIds,
                segmentationsById, resourceSegmentations, resourcesById, resourceIds, campaignResources);
    }

    @NotNull
    private List<CampaignProvidersSettingsDictionary.Segmentation> prepareSegmentationsDictionary(
            @NotNull final CommonDictionaryParameters commonParameters) {
        final List<CampaignProvidersSettingsDictionary.Segmentation> segmentationsDictionary = new ArrayList<>();
        final Stream<Long> sortedSegmentationIds = commonParameters.getSegmentationIds().stream()
                .sorted(Comparator.comparing(s -> commonParameters.getSegmentationsById().get(s).getPriority()));
        sortedSegmentationIds.forEach(segmentationId ->
                addSegmentationToDictionary(segmentationId, commonParameters, segmentationsDictionary));
        return segmentationsDictionary;
    }

    private void addSegmentationToDictionary(final long segmentationId,
                                             @NotNull final CommonDictionaryParameters commonParameters,
                                             @NotNull final List<CampaignProvidersSettingsDictionary.Segmentation> segmentationsDictionary) {
        final Segmentation segmentation = commonParameters.getSegmentationsById().get(segmentationId);
        final Set<Segment> segments = commonParameters.getSegmentsBySegmentationId().get(segmentationId);
        final List<CampaignProvidersSettingsDictionary.Segment> segmentsDictionary = new ArrayList<>();
        final Stream<Segment> sortedSegments = segments.stream().sorted(Comparator.comparing(Segment::getPriority,
                Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(LongIndexBase::getId));
        sortedSegments.forEach(s -> {
            segmentsDictionary.add(new CampaignProvidersSettingsDictionary.Segment(s.getId(),
                    s.getPublicKey(), s.getName(), s.getPriority()));
        });
        segmentationsDictionary.add(new CampaignProvidersSettingsDictionary.Segmentation(segmentation.getId(),
                segmentation.getKey().getPublicKey(), segmentation.getName(), segmentsDictionary, segmentation.getPriority()));
    }

    @NotNull
    private List<CampaignProvidersSettingsDictionary.Provider> prepareProvidersDictionary(@NotNull final Campaign campaign,
                                                                                          @NotNull final CommonDictionaryParameters commonParameters) {
        final ProvidersParameters providersParameters = prepareProvidersParameters(campaign, commonParameters);
        final List<CampaignProvidersSettingsDictionary.Provider> providersDictionary = new ArrayList<>();
        final Stream<Service> sortedServices = providersParameters.getServiceById().values().stream()
                .sorted(Comparator.comparing(Service::getPriority, Comparator.nullsLast(Comparator.naturalOrder()))
                        .thenComparing(LongIndexBase::getId));
        sortedServices.forEach(s -> addProviderToDictionary(s, providersDictionary, providersParameters));
        return providersDictionary;
    }

    private ProvidersParameters prepareProvidersParameters(@NotNull final Campaign campaign,
                                                           @NotNull final CommonDictionaryParameters commonParameters) {
        final Map<Long, CampaignResource> campaignResourceByResourceId = commonParameters.getCampaignResources()
                .stream().collect(Collectors.toMap(CampaignResource::getResourceId, Function.identity()));
        final Map<Long, Set<Segmentation>> segmentationsByResource = commonParameters.getResourceSegmentations()
                .stream().collect(Collectors.groupingBy(rs -> rs.getResource().getId(), HashMap::new,
                        Collectors.mapping(ResourceSegmentation::getSegmentation, Collectors.toSet())));
        // Need empty sets for resources without segmentations
        commonParameters.getResourceIds()
                .forEach(resourceId -> segmentationsByResource.computeIfAbsent(resourceId, k -> new HashSet<>()));
        final Map<Long, Map<Long, List<Segment>>> segmentsBySegmentationByResource = new HashMap<>();
        final Map<Long, Set<Long>> segmentIdsByResourceIds = new HashMap<>();
        prepareSegmentations(segmentationsByResource, commonParameters.getSegmentsBySegmentationId(),
                segmentsBySegmentationByResource, segmentIdsByResourceIds);
        final Map<Long, Set<Resource>> resourcesByService = commonParameters.getResourcesById().values().stream()
                .collect(Collectors.groupingBy(r -> r.getService().getId(), Collectors.toSet()));
        final Map<Long, Service> serviceById = commonParameters.getResourcesById().values().stream()
                .map(Resource::getService).distinct()
                .collect(Collectors.toMap(LongIndexBase::getId, Function.identity()));
        final Set<Long> campaignBigOrderIds = campaign.getBigOrders().stream()
                .map(LongIndexBase::getId).collect(Collectors.toSet());
        final List<Long> sortedCampaignBigOrderIds = campaign.getBigOrders().stream()
                .sorted(Comparator.comparing(LongIndexBase::getId)).map(LongIndexBase::getId).collect(Collectors.toList());

        final Map<Long, ResourceUnit> resourceUnitById = resourceUnitDao.read(commonParameters.getResourceIds());

        final Map<Long, List<CampaignProvidersSettingsDictionary.ResourcePreset>> presetsByServiceId = presetDao.getPresetsByCampaignId(campaign.getId()).stream()
                .collect(Collectors.toMap(CampaignServiceResourcesPreset::getServiceId, CampaignServiceResourcesPreset::getResourcePresets));

        return new ProvidersParameters(campaignResourceByResourceId, segmentsBySegmentationByResource,
                segmentIdsByResourceIds, resourcesByService, serviceById, campaignBigOrderIds, sortedCampaignBigOrderIds, resourceUnitById, presetsByServiceId);
    }

    private List<CampaignProvidersSettingsDictionary.ResourcePreset> preparePresets(final List<CampaignProvidersSettingsDictionary.ResourcePreset> presets,
                                                                                    final ProvidersParameters parameters) {

        final Set<Long> resourceIdsInPresets = presets.stream()
                .filter(p -> parameters.getCampaignResourceByResourceId().containsKey(p.getResourceId()))
                .map(CampaignProvidersSettingsDictionary.ResourcePreset::getResourceId)
                .collect(Collectors.toSet());

        final Map<Long, Map<Long, Set<Long>>> segmentsBySegmentationByResource = new HashMap<>();
        for (final Long resourceId : resourceIdsInPresets) {
            final Map<Long, List<Segment>> segmentsBySegmentation = parameters.getSegmentsBySegmentationByResource().getOrDefault(resourceId, Collections.emptyMap());
            final HashMap<Long, Set<Long>> segmentIdsBySegmentationId = new HashMap<>();
            for (final Long segmentationId : segmentsBySegmentation.keySet()) {
                final List<Segment> segments = segmentsBySegmentation.get(segmentationId);
                final Set<Long> segmentIds = new HashSet<>();
                for (final Segment segment : segments) {
                    segmentIds.add(segment.getId());
                }
                segmentIdsBySegmentationId.put(segmentationId, segmentIds);
            }
            segmentsBySegmentationByResource.put(resourceId, segmentIdsBySegmentationId);
        }

        final List<CampaignProvidersSettingsDictionary.ResourcePreset> resultPresets = new ArrayList<>();
        for (final CampaignProvidersSettingsDictionary.ResourcePreset preset : presets) {
            final long resourceId = preset.getResourceId();
            final Map<Long, Set<Long>> segmentsIdsBySegmentationId = segmentsBySegmentationByResource.get(resourceId);
            if (segmentsIdsBySegmentationId == null) {
                continue;
            }

            final List<CampaignProvidersSettingsDictionary.ResourcePresetSegment> resultSegments = new ArrayList<>();
            for (final CampaignProvidersSettingsDictionary.ResourcePresetSegment segment : preset.getSegments()) {
                final Set<Long> segmentIds = segmentsIdsBySegmentationId.get(segment.getSegmentationId());
                if (segmentIds == null || !segmentIds.contains(segment.getSegmentId())) {
                    continue;
                }
                resultSegments.add(segment);
            }
            resultPresets.add(new CampaignProvidersSettingsDictionary.ResourcePreset(resourceId, resultSegments));
        }


        return resultPresets;
    }

    private void addProviderToDictionary(@NotNull final Service service,
                                         @NotNull final List<CampaignProvidersSettingsDictionary.Provider> providersDictionary,
                                         @NotNull final ProvidersParameters providersParameters) {
        final List<CampaignProvidersSettingsDictionary.Resource> resourcesDictionary = new ArrayList<>();
        final Set<Resource> resources = providersParameters.getResourcesByService().get(service.getId());
        final Stream<Resource> sortedResources = resources.stream().sorted(Comparator.comparing(Resource::getPriority,
                Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(LongIndexBase::getId));
        sortedResources.forEach(r -> addResourceToDictionary(r, resourcesDictionary, providersParameters));

        final List<CampaignProvidersSettingsDictionary.ResourcePreset> presets = preparePresets(providersParameters.getPresetsByServiceId()
                .getOrDefault(service.getId(), Collections.emptyList()), providersParameters);

        providersDictionary.add(new CampaignProvidersSettingsDictionary.Provider(service.getId(),
                service.getKey(), service.getName(), service.getPriority(), resourcesDictionary, presets));
    }

    private void addResourceToDictionary(@NotNull final Resource resource,
                                         @NotNull final List<CampaignProvidersSettingsDictionary.Resource> resourcesDictionary,
                                         @NotNull final ProvidersParameters providersParameters) {
        final CampaignResource campaignResource = providersParameters.getCampaignResourceByResourceId().get(resource.getId());
        final CampaignResource.Settings overrideSettings = campaignResource.getSettings();
        final List<CampaignProvidersSettingsDictionary.ResourceSegmentation> resourceSegmentationsDictionary
                = prepareResourceSegmentations(resource, providersParameters, overrideSettings);
        final List<Long> resourceBigOrdersDictionary = prepareBigOrdersOverrides(providersParameters, overrideSettings);
        final List<CampaignProvidersSettingsDictionary.SegmentsBigOrders> resourceSegmentedBigOrdersDictionary
                = prepareSegmentBigOrderOverrides(resource, providersParameters, overrideSettings);
        final Optional<DiAmount> defaultAmount = campaignResource.getDefaultAmount()
                .map(v -> DiAmount.of(v, resource.getType().getBaseUnit()));

        final ResourceUnit resourceUnit = providersParameters.getResourceUnitsById().get(resource.getId());
        final String defaultUnit = resourceUnit == null ? null : resourceUnit.getDefaultUnit();
        final ResourceUnit.UnitsSettings unitsSettings = resourceUnit == null ? null : resourceUnit.getUnitsSettings();

        resourcesDictionary.add(new CampaignProvidersSettingsDictionary.Resource(resource.getId(),
                resource.getPublicKey(), resource.getName(), resource.getType(), campaignResource.isRequired(),
                campaignResource.isDefaultResource(), defaultAmount.orElse(null), resource.getPriority(),
                resourceSegmentationsDictionary, resourceBigOrdersDictionary, resourceSegmentedBigOrdersDictionary, defaultUnit, unitsSettings));
    }

    @NotNull
    private List<Long> prepareBigOrdersOverrides(
            @NotNull final PerCampaignFrontDictionariesManager.ProvidersParameters providersParameters,
            @NotNull final CampaignResource.Settings overrideSettings) {
        final Set<Long> overriddenBigOrders = new HashSet<>(overrideSettings.getBigOrders());
        final List<Long> resourceBigOrdersDictionary = new ArrayList<>();
        if (!overriddenBigOrders.isEmpty()) {
            providersParameters.getSortedCampaignBigOrderIds().forEach(id -> {
                if (overriddenBigOrders.contains(id)) {
                    resourceBigOrdersDictionary.add(id);
                }
            });
        }
        return resourceBigOrdersDictionary;
    }

    @NotNull
    private List<CampaignProvidersSettingsDictionary.ResourceSegmentation> prepareResourceSegmentations(
            @NotNull final Resource resource,
            @NotNull final PerCampaignFrontDictionariesManager.ProvidersParameters providersParameters,
            @NotNull final CampaignResource.Settings overrideSettings) {
        final Map<Long, CampaignResource.Segmentation> overriddenSegmentationsById = overrideSettings.getSegmentations()
                .stream().collect(Collectors.toMap(CampaignResource.Segmentation::getId, Function.identity()));
        final Map<Long, List<Segment>> baseSegmentsBySegmentationId = providersParameters
                .getSegmentsBySegmentationByResource().get(resource.getId());
        final List<CampaignProvidersSettingsDictionary.ResourceSegmentation> resourceSegmentationsDictionary = new ArrayList<>();
        baseSegmentsBySegmentationId.keySet().stream().sorted().forEach(segmentationId -> {
            final CampaignResource.Segmentation overriddenSegmentation = overriddenSegmentationsById.get(segmentationId);
            if (overriddenSegmentation != null && !overriddenSegmentation.getSegments().isEmpty()) {
                // Segments for segmentation are overridden
                final Set<Long> overriddenSegmentIds = new HashSet<>(overriddenSegmentation.getSegments());
                final List<Long> segmentIds = new ArrayList<>();
                final List<Segment> baseSegments = baseSegmentsBySegmentationId.get(segmentationId);
                baseSegments.forEach(segment -> {
                    if (overriddenSegmentIds.contains(segment.getId())) {
                        segmentIds.add(segment.getId());
                    }
                });
                resourceSegmentationsDictionary
                        .add(new CampaignProvidersSettingsDictionary.ResourceSegmentation(segmentationId, segmentIds));
            } else {
                // Segments for segmentation are not overridden
                resourceSegmentationsDictionary
                        .add(new CampaignProvidersSettingsDictionary.ResourceSegmentation(segmentationId,
                                Collections.emptyList()));
            }
        });
        return resourceSegmentationsDictionary;
    }

    @NotNull
    private List<CampaignProvidersSettingsDictionary.SegmentsBigOrders> prepareSegmentBigOrderOverrides(
            @NotNull final Resource resource,
            @NotNull final PerCampaignFrontDictionariesManager.ProvidersParameters providersParameters,
            @NotNull final CampaignResource.Settings overrideSettings) {
        final List<CampaignProvidersSettingsDictionary.SegmentsBigOrders> resourceSegmentedBigOrdersDictionary = new ArrayList<>();
        final Set<Long> baseAvailableSegmentIds = providersParameters.getSegmentIdsByResourceIds().get(resource.getId());
        overrideSettings.getSegmentsBigOrders().forEach(v -> {
            if (baseAvailableSegmentIds.containsAll(v.getSegments()) && !v.getSegments().isEmpty()
                    && (providersParameters.getCampaignBigOrderIds()
                    .containsAll(v.getBigOrders()) || v.getBigOrders().isEmpty())) {
                final List<Long> segmentIds = v.getSegments().stream().sorted().collect(Collectors.toList());
                final Set<Long> overriddenSegmentsBigOrderIds = new HashSet<>(v.getBigOrders());
                final List<Long> segmentBigOrderIdsDictionary = new ArrayList<>();
                providersParameters.getSortedCampaignBigOrderIds().forEach(id -> {
                    if (overriddenSegmentsBigOrderIds.contains(id)) {
                        segmentBigOrderIdsDictionary.add(id);
                    }
                });
                resourceSegmentedBigOrdersDictionary
                        .add(new CampaignProvidersSettingsDictionary
                                .SegmentsBigOrders(segmentIds, segmentBigOrderIdsDictionary));
            }
        });
        return resourceSegmentedBigOrdersDictionary;
    }

    private void prepareSegmentations(@NotNull final Map<Long, Set<Segmentation>> segmentationsByResource,
                                      @NotNull final Map<Long, Set<Segment>> segmentsBySegmentationId,
                                      @NotNull final Map<Long, Map<Long, List<Segment>>> segmentsBySegmentationByResource,
                                      @NotNull final Map<Long, Set<Long>> segmentIdsByResourceIds) {
        segmentationsByResource.forEach((resourceId, segmentations) -> {
            final Map<Long, List<Segment>> segmentsBySegmentation = new HashMap<>();
            final Set<Long> segmentIds = new HashSet<>();
            segmentations.forEach(segmentation -> {
                final Set<Segment> segments = segmentsBySegmentationId
                        .getOrDefault(segmentation.getId(), Collections.emptySet());
                final List<Segment> sortedSegments = segments.stream().sorted(Comparator.comparing(Segment::getPriority,
                        Comparator.nullsLast(Comparator.naturalOrder())).thenComparing(LongIndexBase::getId))
                        .collect(Collectors.toList());
                segmentsBySegmentation.put(segmentation.getId(), sortedSegments);
                segmentIds.addAll(segments.stream().map(LongIndexBase::getId).collect(Collectors.toSet()));
            });
            segmentsBySegmentationByResource.put(resourceId, segmentsBySegmentation);
            segmentIdsByResourceIds.put(resourceId, segmentIds);
        });
    }

    private static final class CommonDictionaryParameters {

        @NotNull
        private final Map<Long, Set<Segment>> segmentsBySegmentationId;
        @NotNull
        private final Set<Long> segmentationIds;
        @NotNull
        private final Map<Long, Segmentation> segmentationsById;
        @NotNull
        private final Set<ResourceSegmentation> resourceSegmentations;
        @NotNull
        private final Map<Long, Resource> resourcesById;
        @NotNull
        private final Set<Long> resourceIds;
        @NotNull
        private final List<CampaignResource> campaignResources;

        private CommonDictionaryParameters(@NotNull final Map<Long, Set<Segment>> segmentsBySegmentationId,
                                           @NotNull final Set<Long> segmentationIds,
                                           @NotNull final Map<Long, Segmentation> segmentationsById,
                                           @NotNull final Set<ResourceSegmentation> resourceSegmentations,
                                           @NotNull final Map<Long, Resource> resourcesById,
                                           @NotNull final Set<Long> resourceIds,
                                           @NotNull final List<CampaignResource> campaignResources) {
            this.segmentsBySegmentationId = segmentsBySegmentationId;
            this.segmentationIds = segmentationIds;
            this.segmentationsById = segmentationsById;
            this.resourceSegmentations = resourceSegmentations;
            this.resourcesById = resourcesById;
            this.resourceIds = resourceIds;
            this.campaignResources = campaignResources;
        }

        @NotNull
        public Map<Long, Set<Segment>> getSegmentsBySegmentationId() {
            return segmentsBySegmentationId;
        }

        @NotNull
        public Set<Long> getSegmentationIds() {
            return segmentationIds;
        }

        @NotNull
        public Map<Long, Segmentation> getSegmentationsById() {
            return segmentationsById;
        }

        @NotNull
        public Set<ResourceSegmentation> getResourceSegmentations() {
            return resourceSegmentations;
        }

        @NotNull
        public Map<Long, Resource> getResourcesById() {
            return resourcesById;
        }

        @NotNull
        public Set<Long> getResourceIds() {
            return resourceIds;
        }

        @NotNull
        public List<CampaignResource> getCampaignResources() {
            return campaignResources;
        }

    }

    private static final class ProvidersParameters {

        @NotNull
        private final Map<Long, CampaignResource> campaignResourceByResourceId;
        @NotNull
        private final Map<Long, Map<Long, List<Segment>>> segmentsBySegmentationByResource;
        @NotNull
        private final Map<Long, Set<Long>> segmentIdsByResourceIds;
        @NotNull
        private final Map<Long, Set<Resource>> resourcesByService;
        @NotNull
        private final Map<Long, Service> serviceById;
        @NotNull
        private final Set<Long> campaignBigOrderIds;
        @NotNull
        private final List<Long> sortedCampaignBigOrderIds;
        @NotNull
        private final Map<Long, ResourceUnit> resourceUnitsById;
        @NotNull
        private final Map<Long, List<CampaignProvidersSettingsDictionary.ResourcePreset>> presetsByServiceId;

        private ProvidersParameters(@NotNull final Map<Long, CampaignResource> campaignResourceByResourceId,
                                    @NotNull final Map<Long, Map<Long, List<Segment>>> segmentsBySegmentationByResource,
                                    @NotNull final Map<Long, Set<Long>> segmentIdsByResourceIds,
                                    @NotNull final Map<Long, Set<Resource>> resourcesByService,
                                    @NotNull final Map<Long, Service> serviceById,
                                    @NotNull final Set<Long> campaignBigOrderIds,
                                    @NotNull final List<Long> sortedCampaignBigOrderIds,
                                    @NotNull final Map<Long, ResourceUnit> resourceUnitsById,
                                    @NotNull final Map<Long, List<CampaignProvidersSettingsDictionary.ResourcePreset>> presetsByServiceId) {
            this.campaignResourceByResourceId = campaignResourceByResourceId;
            this.segmentsBySegmentationByResource = segmentsBySegmentationByResource;
            this.segmentIdsByResourceIds = segmentIdsByResourceIds;
            this.resourcesByService = resourcesByService;
            this.serviceById = serviceById;
            this.campaignBigOrderIds = campaignBigOrderIds;
            this.sortedCampaignBigOrderIds = sortedCampaignBigOrderIds;
            this.resourceUnitsById = resourceUnitsById;
            this.presetsByServiceId = presetsByServiceId;
        }

        @NotNull
        public Map<Long, CampaignResource> getCampaignResourceByResourceId() {
            return campaignResourceByResourceId;
        }

        @NotNull
        public Map<Long, Map<Long, List<Segment>>> getSegmentsBySegmentationByResource() {
            return segmentsBySegmentationByResource;
        }

        @NotNull
        public Map<Long, Set<Long>> getSegmentIdsByResourceIds() {
            return segmentIdsByResourceIds;
        }

        @NotNull
        public Map<Long, Set<Resource>> getResourcesByService() {
            return resourcesByService;
        }

        @NotNull
        public Map<Long, Service> getServiceById() {
            return serviceById;
        }

        @NotNull
        public Set<Long> getCampaignBigOrderIds() {
            return campaignBigOrderIds;
        }

        @NotNull
        public List<Long> getSortedCampaignBigOrderIds() {
            return sortedCampaignBigOrderIds;
        }

        @NotNull
        public Map<Long, ResourceUnit> getResourceUnitsById() {
            return resourceUnitsById;
        }

        public Map<Long, List<CampaignProvidersSettingsDictionary.ResourcePreset>> getPresetsByServiceId() {
            return presetsByServiceId;
        }
    }

}
