#include "id_manager.h"
#include <maps/libs/common/include/exception.h>

#include <cmath>

namespace maps::wiki::json2ymapsdf {

IdManager& idManager()
{
    static IdManager idManager;
    return idManager;
}

void IdManager::advanceTo(DBID idSequence)
{
    std::lock_guard<std::mutex> lock(mutex_);
    if (lastId_ == 0) {
        lastId_ = idSequence;
        maxOriginalId_ = idSequence;
    }
}

DBID IdManager::uniqueDBID()
{
    return ++lastId_;
}

DBID IdManager::uniqueDBID(DBID id)
{
    if (id == 0) {
        return uniqueDBID();
    }
    REQUIRE(id <= lastId_, "Object id [" << id <<
        "] must be not greater then sequence last id [" << lastId_ << "]");
    std::lock_guard<std::mutex> lock(mutex_);
    auto it = requestedIds_.find(id);
    if (it == requestedIds_.end()) {
        requestedIds_.insert(id);
        return id;
    } else {
        return uniqueDBID();
    }
}

namespace {
DBID ceil(DBID number, int numDigits)
{
    const auto denominator = std::pow(10, numDigits);
    return std::ceil(number / denominator) * denominator;
}
} // namespace

void IdManager::roundUp()
{
    // if maxOriginalId_ == 123
    // roundup(lastId_ =  135) =  200;
    // roundup(lastId_ =  200) =  300;
    // roundup(lastId_ =  999) = 1100;
    // roundup(lastId_ = 1000) = 1100;
    // roundup(lastId_ = 123456) = 123600;
    std::lock_guard<std::mutex> lock(mutex_);
    auto roundUpAddend = maxOriginalId_ / 2 + 1;
    int numDigits = std::floor(std::log10(maxOriginalId_));
    lastId_ = ceil(lastId_ + roundUpAddend, numDigits);
}

} // namespace maps::wiki::json2ymapsdf
