#include "sd_module.h"

#include <saas/deploy_manager/meta/cluster.h>
#include <saas/deploy_manager/modules/resources/common/common.h>
#include <saas/util/external/dc.h>

TSDModule::TSDModule(const TString& sdConfig, const NRTYDeploy::ICommonData& environmentInformation)
    : EnvironmentInformation(environmentInformation)
    , SDConfig(sdConfig)
    {
        if (!sdConfig) {
            Enabled = false;
            return;
        }
        SDOptions.Parse(sdConfig);
        if (!SDOptions.Enabled) {
            INFO_LOG << "Service discovery module disabled, config: " << sdConfig << Endl;
            Enabled = false;
            return;
        }
        Enabled = true;
        Init();
    }

bool TSDModule::AddEndpointSet(const TString& eps) {
    if (!Enabled)
        return false;
    if (Clients.contains(eps))
        return true;
    Clients.emplace(eps, MakeHolder<NYP::NServiceDiscovery::TSDClient>(SDOptions, NYP::NServiceDiscovery::StandaloneCounterFactory));
    TVector<TString> parts = SplitString(eps, "@");
    if (parts.size() != 2)
        return false;
    NYP::NServiceDiscovery::TEndpointSetKey key(parts[0], parts[1]);
    Clients.at(eps)->RegisterEndpointSet<TProviderCallback>(key, TProviderCallback());
    try {
        Clients.at(eps)->Start();
    } catch (...) {
        ERROR_LOG << "Cannot start endpointset sd: eps=" << eps << " error=" << CurrentExceptionMessage() << Endl;
        //todo: signal 'unresolved-endpoints', alert
        return false;
    }
    return true;
}

void TSDModule::TProviderCallback::Update(const NYP::NServiceDiscovery::TEndpointSetEx& endpointSet) {
    for (ssize_t i = 0; i < endpointSet.endpoints_size(); ++i) {
        const TString fqdn = endpointSet.endpoints(i).fqdn();
        const TString ip = endpointSet.endpoints(i).ip6_address();
        const TString oldIp = TDatacenterUtil::Instance().GetPodIP(fqdn);
        if (ip != oldIp && ip != "") {
            TDatacenterUtil::Instance().SetPodIP(fqdn, ip);
        }
    }
}

void TSDModule::SearchMapScannerEndpointsCallback::OnEndpointSet(const NSearchMapParser::TSearchMapHost& host,
    const NSearchMapParser::TSearchMapReplica& /*replica*/, const NSearchMapParser::TSearchMapService& /*service*/) {

    Owner.AddEndpointSet(host.Name);
}

void TSDModule::Init() {
    TVector<TString> ctypes;
    if (!NRTYDeploy::GetCTypesFromStorage(EnvironmentInformation.GetStorage(), ctypes)) {
        ERROR_LOG << "Cannot GetCTypesFromStorage" << Endl;
        return;
    }
    for (auto& ctype : ctypes) {
        const NSaas::TClusterConst* clusterPtr = NSaas::TClusterLocker::DefineConst(EnvironmentInformation, ctype);
        if (!clusterPtr) {
            ERROR_LOG << "EndpointSets error: cannot get cluster for " << ctype << Endl;
            continue;
        }
        SearchMapScannerEndpointsCallback epsCb(*this);
        clusterPtr->RTYSearchMap().Scan(epsCb);
    }
}
