#include "slots_placement.h"

#include <util/generic/hash_set.h>

namespace NRTYDeploy {

    bool PlaceIteration(TVector<NRTYCluster::TSlotData>& placement, const ui32 idx, const ui32 size,
        TSet<NRTYCluster::TSlotData>& usedSet,
        const TMap<NSearchMapParser::TShardsInterval, THashSet<TString>>& forbiddenSet,
        const TMap<TString, NRTYCluster::TSlotData>& slots,
        const TVector<NSearchMapParser::TShardsInterval>& intervals)
    {
        if (idx == size) {
            return true;
        }
        const NSearchMapParser::TShardsInterval& currentInterval = intervals[idx];
        for (const auto& slotPair: slots) {
            const NRTYCluster::TSlotData& slotData = slotPair.second;
            if (usedSet.contains(slotData))
                continue;
            const auto it = forbiddenSet.find(currentInterval);
            if (it != forbiddenSet.cend() && it->second.contains(slotData.ShortHost()))
                continue;
            if (placement.size() > idx)
                placement[idx] = slotData;
            else
                placement.push_back(slotData);
            usedSet.insert(slotData);
            if (PlaceIteration(placement, idx + 1, size, usedSet, forbiddenSet, slots, intervals))
                return true;
            usedSet.erase(slotData);
        }
        return false;
    }

    TMaybe<TVector<NRTYCluster::TSlotData>> PlaceSlots(const TMap<TString, NRTYCluster::TSlotData>& slots,
        const TMap<NSearchMapParser::TShardsInterval, THashSet<TString>>& forbiddenSet,
        const TVector<NSearchMapParser::TShardsInterval>& intervals)
    {
        TVector<NRTYCluster::TSlotData> placement;
        placement.reserve(intervals.size());
        TSet<NRTYCluster::TSlotData> used;
        if (PlaceIteration(placement, 0, intervals.size(), used, forbiddenSet, slots, intervals))
            return std::move(placement);
        else
            return Nothing();
    }

} // namespace NRTYDeploy
