#pragma once

#include <saas/deploy_manager/scripts/common/deploy/deploy_builder.h>
#include <saas/deploy_manager/scripts/common/slots_allocator/allocator.h>

namespace NRTYDeploy {
    class TFiltersAggregator {
    public:
        TFiltersAggregator(const NRTYCluster::TSlotsAllocator& allocator,
                           const IControllersChecker* controllers,
                           NRTYDeployInfo::IDeployComponentInfo::TPtr componentInfo,
                           NRTYDeployInfo::IDeployServiceInfo::TPtr serviceInfo,
                           ui64 slotsCount)
            : PoolFilter(new NRTYCluster::TPoolFilter(*componentInfo, true))
            , UsedServers(new NRTYCluster::TUsedServersFilter(*serviceInfo))
        {
            TVector<NSearchMapParser::TSearchMapHost> usedSlots = componentInfo->GetUsedSlots();
            TVector<NSearchMapParser::TSearchMapHost> currentServiceSlots = serviceInfo->GetUsedSlots();
            for (auto&& i : usedSlots) {
                UsedSlotsByServer[i.GetShortHostName()]++;
            }

            for (auto&& i : currentServiceSlots) {
                CurrentServiceSlotsByServer[i.GetShortHostName()]++;
            }

            GlobalFilters.RegisterFilter(PoolFilter);
            GlobalFilters.RegisterFilter(new IControllersChecker::TFilter(controllers));

            AllocFilters.RegisterFilter(PoolFilter);
            if (!allocator.CustomSlots.empty())
                AllocFilters.RegisterFilter(new NRTYCluster::TCustomSlotsFilter(allocator.CustomSlots));
            else if (allocator.PrefferedDCOnly)
                AllocFilters.RegisterFilter(new NRTYCluster::TPreferredDCListFilter(allocator.PrefDCs));
            if (allocator.OneServerOnSlot)
                AllocFilters.RegisterFilter(UsedServers);
            if (!allocator.MultiDC)
                AllocFilters.RegisterFilter(new NRTYCluster::TDCResourcesFilter(slotsCount, allocator.OneServerOnSlot));
            if (allocator.OneServerOnSlot)
                AllocFilters.RegisterFilter(new NRTYCluster::TOneSlotFilter);

            AllocFilters.RegisterFilter(new NRTYCluster::TCommonRankerFilter(UsedSlotsByServer, CurrentServiceSlotsByServer, allocator, slotsCount));
        }

        const NRTYCluster::TFiltersCollection& GetAllocFilters()  const {
            return AllocFilters;
        }

        const NRTYCluster::TFiltersCollection& GetGlobalFilters()  const {
            return GlobalFilters;
        }

        void AddInPool(const NSearchMapParser::TSearchMapHost& host) {
            UsedServers->AddInPool(host.GetShortHostName());
            PoolFilter->AddInPool(host.GetShortSlotName());
        }

    private:

        TMap<TString, ui32> UsedSlotsByServer;
        TMap<TString, ui32> CurrentServiceSlotsByServer;

        NRTYCluster::TFiltersCollection GlobalFilters;
        NRTYCluster::TFiltersCollection AllocFilters;

        TAtomicSharedPtr<NRTYCluster::TPoolFilter> PoolFilter;
        TAtomicSharedPtr<NRTYCluster::TUsedServersFilter> UsedServers;
    };
}
