local json = require "cjson"
require "qna_maker.logger" -- require utilizado para pm-cli/provisioningmanager
local utils = require "qna_maker.utils"
local m_models = require("qna_maker.models")
local m_qnaMakerModels = m_models:GetModels()
local m_endpointkeys = require "qna_maker.endpointkeys"
local m_knowledgeBase = require "qna_maker.knowledgeBase"
local m_operations = require "qna_maker.operations"
local m_runtime = require "qna_maker.runtime"

module(..., package.seeall)

--[[
	API - URL BASE
]]--
local m_api_current_version = "4.0"
local API_QNA_MAKER_URIS

local function SetVersionBaseURIs ()
	local urisVersions = {
	-- VERSION 4.0
		["4.0"] = {
			ENDPOINTKEYS         = [[https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/endpointkeys/]],
			KNOWLEDGEBASES       = [[https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/knowledgebases/]],
			OPERATIONS           = [[https://westus.api.cognitive.microsoft.com/qnamaker/v4.0/operations/]],
			--"https://icqnamaker.azurewebsites.net/qnamaker/knowledgebases/27d1a6b3-99c5-430e-80d3-751c70719d61/generateAnswer"
			RUNTIME_ENDPOINT_URL = [[%s/qnamaker%s/generateAnswer]],
			RUNTIME_ENDPOINT_URL_V2 = [[%s/qnamaker%s/generateAnswerV2]] -- fede
		}
	}
	API_QNA_MAKER_URIS = urisVersions[m_api_current_version]
	assert(API_QNA_MAKER_URIS)
	LogInfo("***********************************************************")
	LogInfo("[QNA_MAKER:api] Qna Maker URIs version: '%s'.", m_api_current_version)
	for name, uri in pairs(API_QNA_MAKER_URIS) do
		LogInfo("[QNA_MAKER:api] %s: %s", name, uri)
	end
	LogInfo("***********************************************************")
end
SetVersionBaseURIs()
----------------------------------

local function GetFirstVccOcpApimSubscriptionKey (vcc)
	local subscriptionsKeys, total = m_qnaMakerModels.VCCs.GetVccOcpApimSubscriptionKey(vcc)
	LogDebug("[QNA_MAKER_API:GetFirstVccOcpApimSubscriptionKey] Total : '%s' subscriptionsKeys: '%s'", total, subscriptionsKeys)
	assert(total > 0)
	local firstSubscription = next(subscriptionsKeys)
	LogDebug("[QNA_MAKER_API:GetFirstVccOcpApimSubscriptionKey] First subscriptions Key: '%s'", firstSubscription)
	return firstSubscription
end

local function GetFirstVccOcpApimSubscriptionKeyV2 (vcc) -- fede
	local subscriptionsKeys, total = m_qnaMakerModels.VCCs.GetVccOcpApimSubscriptionKeyV2(vcc)
	LogDebug("[QNA_MAKER_API:GetFirstVccOcpApimSubscriptionKeyV2] Total : '%s' subscriptionsKeys: '%s'", total, subscriptionsKeys)
	assert(total > 0)
	local firstSubscription = next(subscriptionsKeys)
	LogDebug("[QNA_MAKER_API:GetFirstVccOcpApimSubscriptionKeyV2] First subscriptions Key: '%s'", firstSubscription)
	return firstSubscription
end

local function DeleteKnowledgeBaseFromCassandra (vcc, kbId)
	LogInfo("[QNA_MAKER_API:DeleteKnowledgeBaseFromCassandra] Deleting KnowledgeBase '%s' VCC: '%s' from Cassandra Database.", kbId, vcc)
	m_qnaMakerModels.VCCs.RemoveKnowledgeBase(vcc, kbId)
end

local function GetKnowledgeBaseFromCassandra (vcc, kbId)
	LogInfo("[QNA_MAKER_API:GetKnowledgeBaseFromCassandra] Retrieving KnowledgeBase '%s' VCC: '%s' from Cassandra Database.", kbId, vcc)
	return m_qnaMakerModels.VCCs.GetKnowledgeBase(vcc, kbId)
end

local function ValidateVCC (vcc)
	assert(type(vcc) == "string")
	if vcc:lower() == "system" then
		return false, {code = 404, reason = "Unable to assign/unassign subscription key to system vcc", errType = "inconcert"}
	end
	local vccExists = m_qnaMakerModels.VCCs.VCCExists(vcc)
	if not vccExists then
		return false, {code = 404, reason = "VCC does not exist", errType = "inconcert"}
	end
	return true
end

function EnableLogger (enabled)
	-- Funcion "SetEnabledLogger" existente en qna_maker.logger
	if type(SetEnabledLogger) == "function" then
		SetEnabledLogger(enabled)
	end
end

function GetBaseURI (id)
	assert(type(id) == "string")
	local baseURI = API_QNA_MAKER_URIS[id]
	assert(baseURI)
	return baseURI
end

function MakeCompleteURI (uriBaseId, uri, ...)
	assert(type(uriBaseId) == "string")
	assert(type(uri) == "string")
	local args = {...}
	local baseURI = GetBaseURI(uriBaseId)
	return baseURI .. uri:format(unpack(args))
end

--[[
]]--
function GetEndpointKeys (vcc)
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	return m_endpointkeys.GetEndpointKeys(ocpApimSubscriptionKey)
end

function GetEndpointKeysV2 (vcc) -- fede
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	return m_endpointkeys.GetEndpointKeysV2(ocpApimSubscriptionKey)
end

--[[
]]--
function LoadKnowledgebases (vcc)
	assert(vcc)
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	return m_knowledgeBase.Load(ocpApimSubscriptionKey)
end

function LoadKnowledgebasesV2 (vcc) -- fede
	assert(vcc)
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	return m_knowledgeBase.Load(ocpApimSubscriptionKey)
end

--[[
]]--
function LoadKnowledgebasesFromCassandra (vcc)
	assert(vcc)
	local knowledgeBases = m_qnaMakerModels.VCCs.LoadKnowledgeBases(vcc)
	local total = utils.GetRowCount(knowledgeBases)
	return knowledgeBases, total
end

--[[
]]--
function DownloadKnowledgebase (kbId, vcc)
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local environment = "Test"
	return m_knowledgeBase.Download(kbId, environment, ocpApimSubscriptionKey)
end

function DownloadKnowledgebaseV2 (kbId, vcc) -- fede
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local environment = "Test"
	return m_knowledgeBase.Download(kbId, environment, ocpApimSubscriptionKey)
end

--[[
]]--
function GetKnowledgebaseDetail (kbId, vcc)
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	return m_knowledgeBase.GetDetail(kbId, ocpApimSubscriptionKey)
end

function GetKnowledgebaseDetailV2 (kbId, vcc) -- fede
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	return m_knowledgeBase.GetDetailV2(kbId, ocpApimSubscriptionKey)
end

--[[
]]--
function RemoveKnowledgebaseOnlyCassandra (vcc)
	assert(type(vcc) == "string")
	LogInfo("[QNA_MAKER_API:RemoveKnowledgebaseOnlyCassandra] Removing KnowledgeBase in VCC: '%s' only Cassandra Database.", vcc)
	local vccKnowledgeBases, total = LoadKnowledgebasesFromCassandra(vcc)
	if total < 1 then
		return false, {code = 404, reason = "vcc has no assigned knowledgeBase", errType = "inconcert", vcc = vcc, response = vccKnowledgeBases}
	end
	local kbId = next(vccKnowledgeBases)
	DeleteKnowledgeBaseFromCassandra(vcc, kbId)
	return true, {code = 200, reason = "knowledge Base has been removed from cassandra", errType = "inconcert", vcc = vcc, kbId = kbId}
end

--[[
]]--
function GetVccKnowledgebase (vcc)
	assert(type(vcc) == "string")
	local vccKnowledgeBases, total = LoadKnowledgebasesFromCassandra(vcc)
	if total < 1 then
		return false, {code = 404, reason = "vcc has no assigned knowledgeBase", errType = "inconcert", vcc = vcc}
	end
	if total > 1 then
		return false, {code = 400, reason = "vcc is assigned more than one knowledgeBase", errType = "inconcert", vcc = vcc}
	end
	local vccKnowledgeBaseInfo
	for id, info in pairs(vccKnowledgeBases) do
		vccKnowledgeBaseInfo = info
		break
	end
	local kbId = vccKnowledgeBaseInfo.kbId
	local success, encodedKnowledgebase = DownloadKnowledgebase(kbId, vcc)
	--LogDebug("****** >> encodedKnowledgebase: " .. encodedKnowledgebase)
	if not success then
		local err = encodedKnowledgebase
		return false, err
	end
	local knowledgebase = json.decode(encodedKnowledgebase)
	knowledgebase.inconcertInfo = vccKnowledgeBaseInfo
	encodedKnowledgebase = json.encode(knowledgebase)
	return true, encodedKnowledgebase
end

--[[
]]--
function CreateKnowledgeBase (info, vcc)
	assert(type(info) == "table")
	assert(type(vcc) == "string")
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local success, response = m_knowledgeBase.Create(info, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end
	-- -- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
	-- local newId = utils.SanitizeId(response)
	-- info.id = newId
	-- info.activeVersion = info.activeVersion or m_defaultAppVersion
	-- m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, newId, info)
	return true, response
end

function CreateKnowledgeBaseV2 (info, vcc) -- fede
	assert(type(info) == "table")
	assert(type(vcc) == "string")
	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local success, response = m_knowledgeBase.Create(info, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end
	-- -- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
	-- local newId = utils.SanitizeId(response)
	-- info.id = newId
	-- info.activeVersion = info.activeVersion or m_defaultAppVersion
	-- m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, newId, info)
	return true, response
end

local function UpdateVccEndpointKeysInfo (vcc)
	-------------------------------------------------------------------
	-- 1 Obtengo Info desde la Base de Datos de Inconcert (cassandra)
	--
	local vccKnowledgeBases, total = LoadKnowledgebasesFromCassandra(vcc)
	if total ~= 1 then
		return false, {code = 404, reason = "vcc has no assigned knowledgeBase", errType = "inconcert", vcc = vcc}
	end
	local vccCurrentKnowledgeBase
	for _,v in pairs(vccKnowledgeBases) do
		vccCurrentKnowledgeBase = v
		break
	end
	if not vccCurrentKnowledgeBase then
		return false, {}
	end
	local kbId = vccCurrentKnowledgeBase.kbId or vccCurrentKnowledgeBase.id

	local mustUpdateDB = false -- flag para saber si tiene que actualizar en cassandra la info del "hostName" y de los "endpointKeys"

	-------------------------------------------------------------------
	-- 2 Obtengo el "hostName", Info contra el API de QnA Maker 
	--
	local hostName = vccCurrentKnowledgeBase.hostName
	if not hostName then
		local success, encodedKnowledgeBases = LoadKnowledgebases(vcc)
		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 2 (Obtengo el hostName desde el API de QnA Maker) Generating Answer VCC: '%s' Success: '%s', encodedKnowledgeBases: %s", vcc, success, encodedKnowledgeBases)
		if not success then
			return false, encodedKnowledgeBases
		end
		local knowledgeBases = json.decode(encodedKnowledgeBases)
		local knowledgeBase

		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] Buscando VCC kbId '%s' en la BD de QnA Maker.", kbId)

		for _, info in ipairs(knowledgeBases.knowledgebases or {}) do
			if info.id == kbId then
				knowledgeBase = info
				break
			end
		end

		if not knowledgeBase then
			return false, {}
		end

		hostName = knowledgeBase.hostName
		mustUpdateDB = true -- tengo que actualizar la info del VCC en cassandra
	--else
	--	LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 2 (Obtengo el hostName desde Cassandra)")
	end

	-------------------------------------------------------------------
	-- 3 Obtengo los "endpointKeys", Info contra el API de QnA Maker 
	--
	local endpointKeys = vccCurrentKnowledgeBase.endpointKeys
	if not endpointKeys then
		local success, encodedEndpointKeys = GetEndpointKeys(vcc)
		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 3 (Obtengo los endpointKeys desde el API de QnA Maker)  Generating Answer VCC: '%s' Success: '%s', encodedEndpointKeys: %s", vcc, success, encodedEndpointKeys)
		if not success then
			return false, encodedEndpointKeys
		end
		endpointKeys = json.decode(encodedEndpointKeys)
		mustUpdateDB = true -- tengo que actualizar la info del VCC en cassandra
	--else
	--	LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 3 (Obtengo los endpointKeys desde Cassandra)")
	end
	local primaryEndpointKey = endpointKeys.primaryEndpointKey

	-------------------------------------------------------------------
	-- 4 Guardo en cassandra, info del "hostName" y de los "endpointKeys"
	--
	if mustUpdateDB then
		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 4 Actualizo en cassandra info del 'hostName' y de los 'endpointKeys'")
		local vccInfo = {
			hostName = hostName,
			endpointKeys = endpointKeys
		}
		m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, kbId, vccInfo)
	end

	-------------------------------------------------------------------
	-- 5 Ahora sí, con la información que se ha obtenido armo la Info del POST del Answer.
	--
	local resourceLocation = vccCurrentKnowledgeBase.resourceLocation

	return true, hostName, resourceLocation, primaryEndpointKey
end

local function UpdateVccEndpointKeysInfoV2 (vcc) -- fede
	-------------------------------------------------------------------
	-- 1 Obtengo Info desde la Base de Datos de Inconcert (cassandra)
	--
	local vccKnowledgeBases, total = LoadKnowledgebasesFromCassandra(vcc) 
	if total ~= 1 then
		return false, {code = 404, reason = "vcc has no assigned knowledgeBase", errType = "inconcert", vcc = vcc}
	end
	local vccCurrentKnowledgeBase
	for _,v in pairs(vccKnowledgeBases) do
		vccCurrentKnowledgeBase = v
		break
	end
	if not vccCurrentKnowledgeBase then
		return false, {}
	end
	local kbId = vccCurrentKnowledgeBase.kbId or vccCurrentKnowledgeBase.id

	local mustUpdateDB = false -- flag para saber si tiene que actualizar en cassandra la info del "hostName" y de los "endpointKeys"

	-------------------------------------------------------------------
	-- 2 Obtengo el "hostName", Info contra el API de QnA Maker 
	--
	local hostName = vccCurrentKnowledgeBase.hostName
	if not hostName then
		local success, encodedKnowledgeBases = LoadKnowledgebasesV2(vcc)
		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 2 (Obtengo el hostName desde el API de QnA Maker) Generating Answer VCC: '%s' Success: '%s', encodedKnowledgeBases: %s", vcc, success, encodedKnowledgeBases)
		if not success then
			return false, encodedKnowledgeBases
		end
		local knowledgeBases = json.decode(encodedKnowledgeBases)
		local knowledgeBase

		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] Buscando VCC kbId '%s' en la BD de QnA Maker.", kbId)

		for _, info in ipairs(knowledgeBases.knowledgebases or {}) do
			if info.id == kbId then
				knowledgeBase = info
				break
			end
		end

		if not knowledgeBase then
			return false, {}
		end

		hostName = knowledgeBase.hostName
		mustUpdateDB = true -- tengo que actualizar la info del VCC en cassandra
	--else
	--	LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 2 (Obtengo el hostName desde Cassandra)")
	end

	-------------------------------------------------------------------
	-- 3 Obtengo los "endpointKeys", Info contra el API de QnA Maker 
	--
	local endpointKeys = vccCurrentKnowledgeBase.endpointKeys
	if not endpointKeys then
		local success, encodedEndpointKeys = GetEndpointKeysV2(vcc)
		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 3 (Obtengo los endpointKeys desde el API de QnA Maker)  Generating Answer VCC: '%s' Success: '%s', encodedEndpointKeys: %s", vcc, success, encodedEndpointKeys)
		if not success then
			return false, encodedEndpointKeys
		end
		endpointKeys = json.decode(encodedEndpointKeys)
		mustUpdateDB = true -- tengo que actualizar la info del VCC en cassandra
	--else
	--	LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 3 (Obtengo los endpointKeys desde Cassandra)")
	end
	local primaryEndpointKey = endpointKeys.primaryEndpointKey

	-------------------------------------------------------------------
	-- 4 Guardo en cassandra, info del "hostName" y de los "endpointKeys"
	--
	if mustUpdateDB then
		LogDebug("[QNA_MAKER_API:UpdateVccEndpointsInfo] 4 Actualizo en cassandra info del 'hostName' y de los 'endpointKeys'")
		local vccInfo = {
			hostName = hostName,
			endpointKeys = endpointKeys
		}
		m_qnaMakerModels.VCCs.UpdateKnowledgeBaseV2(vcc, kbId, vccInfo)
	end

	-------------------------------------------------------------------
	-- 5 Ahora sí, con la información que se ha obtenido armo la Info del POST del Answer.
	--
	local resourceLocation = vccCurrentKnowledgeBase.resourceLocation

	return true, hostName, resourceLocation, primaryEndpointKey
end

--[[
	Al nombre de la "Knowledge base" le concatena el VCC y el ClusterId.
	Ej:
		Recibe : ElNombre
		Retorna: ElNombre@ElVcc - i6BetaCaroteno
--]]
local function MakeNameKnowledgebaseForVcc (name, vcc)
	if not name then
		return
	end
	local newName = name
	-- Le agrego el VCC al Name
	if vcc then
		newName =  newName .. "@" .. vcc
	end
	-- Le agrego el Cluster ID
	local clusterId = os.getenv("CLUSTER_ID") or "NONE"
	if clusterId then
		newName =  newName .. " - " .. clusterId
	end
	return newName
end

--[[
]]--
function CreateAndWaitKnowledgeBase (info, vcc)
	assert(type(info) == "table")
	assert(type(vcc) == "string")

	local vccKnowledgeBases, total = LoadKnowledgebasesFromCassandra(vcc)
	if total > 0 then
		local vccKnowledgeBaseInfo
		for id, info in pairs(vccKnowledgeBases) do
			vccKnowledgeBaseInfo = info
			break
		end
		local kbId = vccKnowledgeBaseInfo.kbId
		LogError("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] Already exist knowledgeBase '%s' in VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "already exist knowledgeBase in vcc", errType = "inconcert", vcc = vcc, kbId = kbId}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local clonedInfo = utils.DeepCopy(info)
	clonedInfo.name = MakeNameKnowledgebaseForVcc(clonedInfo.name, vcc)
	local success, response = m_knowledgeBase.Create(clonedInfo, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end

	local function OperationHasFinished (operationState)
		LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] OperationHasFinished - operationState '%s'.", operationState)
		if operationState == "succeeded" then
			return true, "succeeded"
		elseif operationState == "failed" then
			return true, "failed"
		else
			return false, operationState
		end
	end

	local function ValidateOperation (operationDetail)
		local operationState = (operationDetail.operationState or ""):lower()
		LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] ValidateOperation - operationDetail '%s'.", operationDetail)
		local hasFinished, state = OperationHasFinished(operationState)
		if hasFinished then
			local kbId
			if state == "succeeded" then
				local resourceLocation = operationDetail.resourceLocation
				LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] ValidateOperation - operationDetail.resourceLocation '%s'.", resourceLocation or "")
				-- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
				kbId = utils.SanitizeId(resourceLocation)
				info.id = kbId
				for name, value in pairs(operationDetail) do
					info[name] = value
				end

				m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, kbId, info)
				UpdateVccEndpointKeysInfo(vcc)
			end
			return true, state, kbId
		end
		return false, state
	end

	local operationId = response.operationId
	local operationState = response.operationState

	local isFinished, state, kbId = ValidateOperation(response)
	if isFinished then
		if state == "succeeded" then
			response.kbId = kbId
			return true, response
		end
		return false, response
	end

	require "socket"
	local totalRetries = 5
	local waitingSec = 5
	local retry = 1

	while retry <= totalRetries do
		LogDebug("")
		LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] Get Operation Detail. Retry '%s'.", retry)

		local success, encodedDetailResponse = GetOperationDetails(operationId, vcc)
		if success then
			local detailResponse = json.decode(encodedDetailResponse)
			local isFinished, state, kbId = ValidateOperation(detailResponse)
			if isFinished then
				if state == "succeeded" then
					detailResponse.kbId = kbId
					return true, detailResponse
				end
				return false, detailResponse
			end
		end

		socket.sleep(waitingSec)
		retry = retry + 1
	end

	return true, response
end

function CreateAndWaitKnowledgeBaseV2 (info, vcc) -- fede
	assert(type(info) == "table")
	assert(type(vcc) == "string")

	local vccKnowledgeBases, total = LoadKnowledgebasesFromCassandra(vcc)
	if total > 0 then
		local vccKnowledgeBaseInfo
		for id, info in pairs(vccKnowledgeBases) do
			vccKnowledgeBaseInfo = info
			break
		end
		local kbId = vccKnowledgeBaseInfo.kbId
		LogError("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] Already exist knowledgeBase '%s' in VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "already exist knowledgeBase in vcc", errType = "inconcert", vcc = vcc, kbId = kbId}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local clonedInfo = utils.DeepCopy(info)
	clonedInfo.name = MakeNameKnowledgebaseForVccV2(clonedInfo.name, vcc)
	local success, response = m_knowledgeBase.Create(clonedInfo, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end

	local function OperationHasFinished (operationState)
		LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] OperationHasFinished - operationState '%s'.", operationState)
		if operationState == "succeeded" then
			return true, "succeeded"
		elseif operationState == "failed" then
			return true, "failed"
		else
			return false, operationState
		end
	end

	local function ValidateOperation (operationDetail)
		local operationState = (operationDetail.operationState or ""):lower()
		LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] ValidateOperation - operationDetail '%s'.", operationDetail)
		local hasFinished, state = OperationHasFinished(operationState)
		if hasFinished then
			local kbId
			if state == "succeeded" then
				local resourceLocation = operationDetail.resourceLocation
				LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] ValidateOperation - operationDetail.resourceLocation '%s'.", resourceLocation or "")
				-- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
				kbId = utils.SanitizeId(resourceLocation)
				info.id = kbId
				for name, value in pairs(operationDetail) do
					info[name] = value
				end

				m_qnaMakerModels.VCCs.UpdateKnowledgeBaseV2(vcc, kbId, info)
				UpdateVccEndpointKeysInfoV2(vcc)
			end
			return true, state, kbId
		end
		return false, state
	end

	local operationId = response.operationId
	local operationState = response.operationState

	local isFinished, state, kbId = ValidateOperation(response)
	if isFinished then
		if state == "succeeded" then
			response.kbId = kbId
			return true, response
		end
		return false, response
	end

	require "socket"
	local totalRetries = 5
	local waitingSec = 5
	local retry = 1

	while retry <= totalRetries do
		LogDebug("")
		LogDebug("[QNA_MAKER_API:CreateAndWaitKnowledgeBase] Get Operation Detail. Retry '%s'.", retry)

		local success, encodedDetailResponse = GetOperationDetailsV2(operationId, vcc)
		if success then
			local detailResponse = json.decode(encodedDetailResponse)
			local isFinished, state, kbId = ValidateOperation(detailResponse)
			if isFinished then
				if state == "succeeded" then
					detailResponse.kbId = kbId
					return true, detailResponse
				end
				return false, detailResponse
			end
		end

		socket.sleep(waitingSec)
		retry = retry + 1
	end

	return true, response
end

--[[
]]--
function UpdateKnowledgeBase (info, vcc)
	assert(type(vcc) == "string")
	assert(type(info) == "table")
	--LogDebug("1--------> %s", json.encode(info))
	local kbId = info.kbId
	local currentKnowledgeBase = GetKnowledgeBaseFromCassandra(vcc, kbId)
	if not currentKnowledgeBase then
		LogError("[QNA_MAKER_API:UpdateKnowledgeBase] Error Updating KnowledgeBase: '%s'. This KnowledgeBase does not belong VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "knowledgeBase does not belong vcc", errType = "inconcert", kbId = kbId, vcc = vcc}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	-- new
	local add = {
		qnaList = {}
	}
	for _, item in ipairs(info.add or {}) do
		table.insert(add.qnaList, {
			--id = 0,
			answer = item.answer,
			questions = item.questions,
			metadata = item.metadata
			-- source = "Editorial",
			-- context = {
				-- isContextOnly = false,
				-- prompts = {}
			-- }
		})
	end
	info.add = add

	-- delete
	local delete = {
		ids = {}
	}
	for _, id in ipairs(info.delete or {}) do
		table.insert(delete.ids, tonumber(id))
	end
	info.delete = delete

	-- update
	local update = {
		name = MakeNameKnowledgebaseForVcc(info.name, vcc),
		qnaList = {}
	}
	for _, item in ipairs(info.update or {}) do
		table.insert(update.qnaList, {
			id = item.id,
			answer = item.answer,
			questions = item.questions,
			metadata = item.metadata
		})
	end

	info.update = update
	--LogDebug("2--------> %s", json.encode(info))
	local success, response = m_knowledgeBase.Update(info, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end

	info.name = currentKnowledgeBase.name or info.name
	m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, kbId, info)
	return true, response
end

function UpdateKnowledgeBaseV2 (info, vcc) -- fede
	assert(type(vcc) == "string")
	assert(type(info) == "table")
	--LogDebug("1--------> %s", json.encode(info))
	local kbId = info.kbId
	local currentKnowledgeBase = GetKnowledgeBaseFromCassandraV2(vcc, kbId)
	if not currentKnowledgeBase then
		LogError("[QNA_MAKER_API:UpdateKnowledgeBase] Error Updating KnowledgeBase: '%s'. This KnowledgeBase does not belong VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "knowledgeBase does not belong vcc", errType = "inconcert", kbId = kbId, vcc = vcc}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	-- new
	local add = {
		qnaList = {}
	}
	for _, item in ipairs(info.add or {}) do
		table.insert(add.qnaList, {
			--id = 0,
			answer = item.answer,
			questions = item.questions,
			metadata = item.metadata
			-- source = "Editorial",
			-- context = {
				-- isContextOnly = false,
				-- prompts = {}
			-- }
		})
	end
	info.add = add

	-- delete
	local delete = {
		ids = {}
	}
	for _, id in ipairs(info.delete or {}) do
		table.insert(delete.ids, tonumber(id))
	end
	info.delete = delete

	-- update
	local update = {
		name = MakeNameKnowledgebaseForVccV2(info.name, vcc),
		qnaList = {}
	}
	for _, item in ipairs(info.update or {}) do
		table.insert(update.qnaList, {
			id = item.id,
			answer = item.answer,
			questions = item.questions,
			metadata = item.metadata
		})
	end

	info.update = update
	--LogDebug("2--------> %s", json.encode(info))
	local success, response = m_knowledgeBase.Update(info, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end

	info.name = currentKnowledgeBase.name or info.name
	m_qnaMakerModels.VCCs.UpdateKnowledgeBaseV2(vcc, kbId, info)
	return true, response
end

--[[
]]--
function ReplaceKnowledgeBase (info, vcc)
	assert(type(vcc) == "string")
	assert(type(info) == "table")
	assert(type(info.qnaList) == "table")

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local success, response = m_knowledgeBase.Replace(info, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end
	-- -- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
	-- local newId = utils.SanitizeId(response)
	-- info.id = newId
	-- info.activeVersion = info.activeVersion or m_defaultAppVersion
	-- m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, newId, info)
	return true, response
end

function ReplaceKnowledgeBaseV2 (info, vcc) -- fede
	assert(type(vcc) == "string")
	assert(type(info) == "table")
	assert(type(info.qnaList) == "table")

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local success, response = m_knowledgeBase.Replace(info, ocpApimSubscriptionKey)
	if not success then
		return false, response
	end
	-- -- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
	-- local newId = utils.SanitizeId(response)
	-- info.id = newId
	-- info.activeVersion = info.activeVersion or m_defaultAppVersion
	-- m_qnaMakerModels.VCCs.UpdateKnowledgeBase(vcc, newId, info)
	return true, response
end

function DeleteKnowledgeBase (kbId, vcc)
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")

	local currentKnowledgeBase = GetKnowledgeBaseFromCassandra(vcc, kbId)
	if not currentKnowledgeBase then
		LogError("[QNA_MAKER_API:DeleteKnowledgeBase] Error Deleting KnowledgeBase: '%s'. This KnowledgeBase does not belong VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "knowledgeBase does not belong vcc", errType = "inconcert", kbId = kbId, vcc = vcc}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local success, response = m_knowledgeBase.Delete(kbId, ocpApimSubscriptionKey)
	--LogDebug("[QNA_MAKER_API:DeleteKnowledgeBase] Deleting KnowledgeBase: '%s' Success: '%s', Response: %s", kbId, success, response)
	if not success then
		return false, response
	end
	-- Se quita del VCC la App.
	DeleteKnowledgeBaseFromCassandra(vcc, kbId)
	return true, response
end

function DeleteKnowledgeBaseV2 (kbId, vcc) -- fede
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")

	local currentKnowledgeBase = GetKnowledgeBaseFromCassandraV2(vcc, kbId)
	if not currentKnowledgeBase then
		LogError("[QNA_MAKER_API:DeleteKnowledgeBase] Error Deleting KnowledgeBase: '%s'. This KnowledgeBase does not belong VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "knowledgeBase does not belong vcc", errType = "inconcert", kbId = kbId, vcc = vcc}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local success, response = m_knowledgeBase.Delete(kbId, ocpApimSubscriptionKey)
	--LogDebug("[QNA_MAKER_API:DeleteKnowledgeBase] Deleting KnowledgeBase: '%s' Success: '%s', Response: %s", kbId, success, response)
	if not success then
		return false, response
	end
	-- Se quita del VCC la App.
	DeleteKnowledgeBaseFromCassandraV2(vcc, kbId)
	return true, response
end

function PublishKnowledgeBase (kbId, vcc)
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")

	local currentKnowledgeBase = GetKnowledgeBaseFromCassandra(vcc, kbId)
	if not currentKnowledgeBase then
		LogError("[QNA_MAKER_API:PublishKnowledgeBase] Error Publishing KnowledgeBase: '%s'. This KnowledgeBase does not belong VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "knowledgeBase does not belong vcc", errType = "inconcert", kbId = kbId, vcc = vcc}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local success, response = m_knowledgeBase.Publish(kbId, ocpApimSubscriptionKey)
	--LogDebug("[QNA_MAKER_API:PublishKnowledgeBase] Publishing KnowledgeBase: '%s' Success: '%s', Response: %s", kbId, success, response)
	if not success then
		return false, response
	end

	-- local success, encodedOperationDetails = GetOperationDetails(currentKnowledgeBase.operationId, vcc)
	-- if success then
		-- local operationDetails = json.decode(encodedOperationDetails)
		-- return true, operationDetails
	-- end
	return true, response
end

function PublishKnowledgeBaseV2 (kbId, vcc) -- fede
	assert(type(kbId) == "string")
	assert(type(vcc) == "string")

	local currentKnowledgeBase = GetKnowledgeBaseFromCassandraV2(vcc, kbId)
	if not currentKnowledgeBase then
		LogError("[QNA_MAKER_API:PublishKnowledgeBase] Error Publishing KnowledgeBase: '%s'. This KnowledgeBase does not belong VCC '%s'.", kbId, vcc)
		return false, {code = 404, reason = "knowledgeBase does not belong vcc", errType = "inconcert", kbId = kbId, vcc = vcc}
	end

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local success, response = m_knowledgeBase.Publish(kbId, ocpApimSubscriptionKey)
	--LogDebug("[QNA_MAKER_API:PublishKnowledgeBase] Publishing KnowledgeBase: '%s' Success: '%s', Response: %s", kbId, success, response)
	if not success then
		return false, response
	end

	-- local success, encodedOperationDetails = GetOperationDetails(currentKnowledgeBase.operationId, vcc)
	-- if success then
		-- local operationDetails = json.decode(encodedOperationDetails)
		-- return true, operationDetails
	-- end
	return true, response
end

--[[
]]--
function GetOperationDetails (operationId, vcc)
	assert(type(operationId) == "string")
	assert(type(vcc) == "string")

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKey(vcc)
	local success, encodedResponse = m_operations.GetOperationDetails(operationId, ocpApimSubscriptionKey)
	if success then
		local response = json.decode(encodedResponse)
		local resourceLocation = response.resourceLocation
		LogDebug("[QNA_MAKER_API:GetOperationDetails] ValidateOperation - operationDetail.response '%s'.", resourceLocation or "")
		if resourceLocation then
			-- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
			response.kbId = utils.SanitizeId(resourceLocation)
		end
		encodedResponse = json.encode(response)
		return true, encodedResponse
	end
	return false, encodedResponse
end

function GetOperationDetailsV2 (operationId, vcc) -- fede
	assert(type(operationId) == "string")
	assert(type(vcc) == "string")

	local ocpApimSubscriptionKey = GetFirstVccOcpApimSubscriptionKeyV2(vcc)
	local success, encodedResponse = m_operations.GetOperationDetailsV2(operationId, ocpApimSubscriptionKey)
	if success then
		local response = json.decode(encodedResponse)
		local resourceLocation = response.resourceLocation
		LogDebug("[QNA_MAKER_API:GetOperationDetailsV2] ValidateOperation - operationDetail.response '%s'.", resourceLocation or "")
		if resourceLocation then
			-- Elimino caracteres del Id y actualiza la info de la KnownledgeBase en el VCC.
			response.kbId = utils.SanitizeId(resourceLocation)
		end
		encodedResponse = json.encode(response)
		return true, encodedResponse
	end
	return false, encodedResponse
end

------------------------
-- SUBSCRIPTIONS
------------------------
--[[
]]--
function LoadVCCSubscriptions (vcc)
	assert(vcc)
	local subscriptionsKeys = m_qnaMakerModels.VCCs.GetSubscriptionsKeysQnAMaker(vcc)
	local total = utils.GetRowCount(subscriptionsKeys)
	return subscriptionsKeys, total
end

function LoadVCCSubscriptionsV2 (vcc) -- fede
	assert(vcc)
	local subscriptionsKeys = m_qnaMakerModels.VCCs.GetSubscriptionsKeysQnAMakerV2(vcc)
	local total = utils.GetRowCount(subscriptionsKeys)
	return subscriptionsKeys, total
end

--[[
]]--
function LoadVCCsBySubscription (key)
	assert(key)
	local vccs = m_qnaMakerModels.VCCs.LoadVCCsBySubscriptionKey(key)
	local total = utils.GetRowCount(vccs)
	return vccs, total
end

function LoadVCCsBySubscriptionV2 (key) -- fede
	assert(key)
	local vccs = m_qnaMakerModels.VCCs.LoadVCCsBySubscriptionKeyV2(key)
	local total = utils.GetRowCount(vccs)
	return vccs, total
end

--[[
]]--
function AssignSubscriptionKeyToVCC (info)
	assert(type(info) == "table")
	assert(type(info.vcc) == "string")
	assert(type(info.subscriptionKey) == "string")

	local success, response = ValidateVCC(info.vcc)
	if not success then
		return false, response
	end

	-- Asigna al vcc el subscription key
	---- {"subscriptionRegion":"westus","subscriptionName":"Subscription key","subscriptionKey":"d24518b086a248c4ae64afd6e3eb475c"}

	local currentSubscription = {
		subscriptionKey = info.subscriptionKey,
		subscriptionName = info.subscriptionName or info.subscriptionKey,
		-- subscriptionRegion = info.westus or "westus",
		-- isDemo = false
	}
	m_qnaMakerModels.VCCs.AssignSubscriptionKeyToVCC(info.vcc, info.subscriptionKey, currentSubscription)
	return true, {result = "OK"}
end

function AssignSubscriptionKeyToVCCV2 (info) -- fede
	assert(type(info) == "table")
	assert(type(info.vcc) == "string")
	assert(type(info.subscriptionKey) == "string")

	local success, response = ValidateVCC(info.vcc)
	if not success then
		return false, response
	end

	-- Asigna al vcc el subscription key
	---- {"subscriptionRegion":"westus","subscriptionName":"Subscription key","subscriptionKey":"d24518b086a248c4ae64afd6e3eb475c"}

	local currentSubscription = {
		subscriptionKey = info.subscriptionKey,
		subscriptionName = info.subscriptionName or info.subscriptionKey,
		-- subscriptionRegion = info.westus or "westus",
		-- isDemo = false
	}
	m_qnaMakerModels.VCCs.AssignSubscriptionKeyToVCCV2(info.vcc, info.subscriptionKey, currentSubscription)
	return true, {result = "OK"}
end

--[[
]]--
function UnAssignSubscriptionKeyOfVCC (vcc, subscriptionKey)
	assert(type(vcc) == "string")
	assert(type(subscriptionKey) == "string")

	local success, response = ValidateVCC(vcc)
	if not success then
		return false, response
	end

	local _, totalVCCSubscriptionsKeys = LoadVCCSubscriptions(vcc)

	if totalVCCSubscriptionsKeys == 0 then
	-- Este es el caso en el cual VCC NO tiene subscriptions asignadas
		LogInfo("[QNA_MAKER_API:UnAssignSubscriptionKeyOfVCC] VCC " .. vcc .. " not has configured any Subscriptions Keys.")
		return false, {}

	end
	-- Este es el caso en el cual VCC SI tiene subscriptions asignadas

	--LogDebug("[QNA_MAKER_API:UnAssignSubscriptionKeyOfVCC] Updated Apps: %s", json.encode(updatedApps))
	-- Quita del vcc la subscription key
	m_qnaMakerModels.VCCs.UnAssignSubscriptionKeyOfVCC(vcc, subscriptionKey)
	return true, {result = "OK"}
end

function UnAssignSubscriptionKeyOfVCCV2 (vcc, subscriptionKey) -- fede
	assert(type(vcc) == "string")
	assert(type(subscriptionKey) == "string")

	local success, response = ValidateVCC(vcc)
	if not success then
		return false, response
	end

	local _, totalVCCSubscriptionsKeys = LoadVCCSubscriptionsV2(vcc)

	if totalVCCSubscriptionsKeys == 0 then
	-- Este es el caso en el cual VCC NO tiene subscriptions asignadas
		LogInfo("[QNA_MAKER_API:UnAssignSubscriptionKeyOfVCCV2] VCC " .. vcc .. " not has configured any Subscriptions Keys.")
		return false, {}

	end
	-- Este es el caso en el cual VCC SI tiene subscriptions asignadas

	--LogDebug("[QNA_MAKER_API:UnAssignSubscriptionKeyOfVCCV2] Updated Apps: %s", json.encode(updatedApps))
	-- Quita del vcc la subscription key
	m_qnaMakerModels.VCCs.UnAssignSubscriptionKeyOfVCCV2(vcc, subscriptionKey)
	return true, {result = "OK"}
end

--[[
	(RUNTIME) Retorna información para poder realizar una pregutna contra el API.
	Retorna:
		{
		  "primaryEndpointKey": "b86abe85-a840-44bd-91c9-728892b2ea2e",
		  "resourceLocation": "/knowledgebases/4bd4560f-7288-4197-98de-e2403e0c8dfc",
		  "baseURI": "%s/qnamaker%s/generateAnswer",
		  "postData": {
			"question": ""
		  },
		  "headers": {
			"Authorization": "EndpointKey b86abe85-a840-44bd-91c9-728892b2ea2e"
		  },
		  "uri": "https://icqnamaker.azurewebsites.net/qnamaker/knowledgebases/4bd4560f-7288-4197-98de-e2403e0c8dfc/generateAnswer",
		  "hostName": "https://icqnamaker.azurewebsites.net"
		}

	Donde dentro de los atributos que debemos utilziar para armar el request son:
		"uri"
			Es la URL a la cual vamos a realizar el request.
		"headers"
			Es una tabla que contiene los headers de autorización que debemos añadir en el request.
		"postData"
			Contiene el formato del postData que debemos enviar.
			Tenemos que asignar al atributo "postData.question" el valor de nuestra pregunta.
			Opcional puede incluir los metadatos a utilziar como filtro.
]]--
function GetAnswerPostInfo (vcc, info)
	assert(type(vcc) == "string")
	info = info or {question = ""}

	local success, hostName, resourceLocation, primaryEndpointKey = UpdateVccEndpointKeysInfo(vcc)
	if not success then
		local err = hostName
		return false, err
	end

	return true, m_runtime.MakeAnswerPostInfo(info, hostName, resourceLocation, primaryEndpointKey)
end

function GetAnswerPostInfoV2 (vcc, info)
	assert(type(vcc) == "string")
	info = info or {question = ""}

	local success, hostName, resourceLocation, primaryEndpointKey = UpdateVccEndpointKeysInfoV2(vcc)
	if not success then
		local err = hostName
		return false, err
	end

	return true, m_runtime.MakeAnswerPostInfoV2(info, hostName, resourceLocation, primaryEndpointKey)
end

--[[
	POST /knowledgebases/27d1a6b3-99c5-430e-80d3-751c70719d61/generateAnswer
	Host: https://icqnamaker.azurewebsites.net/qnamaker
	Authorization: EndpointKey b86abe85-a840-44bd-91c9-728892b2ea2e
	Content-Type: application/json
	{"question":"<Your question>"}
]]--
function GenerateAnswer (vcc, info, mustUseCurl)
	assert(type(vcc) == "string")
	info = info or {question = ""}

	local success, postInfo = GetAnswerPostInfo(vcc, info)
	if not success then
		return false, postInfo
	end
	return m_runtime.GenerateAnswer(info, postInfo.hostName, postInfo.resourceLocation, postInfo.primaryEndpointKey, mustUseCurl)
end

function GenerateAnswerV2 (vcc, info, mustUseCurl)
	assert(type(vcc) == "string")
	assert(type(info) == "table")
	assert(type(info.question) == "string")
	assert(type(info.metadata.knowledgebases) == "string")

	local VCCSubscriptionsKeys, totalVCCSubscriptionsKeys = LoadVCCSubscriptionsV2(vcc)

	local VCCSubscriptionsKey = {} 
	if totalVCCSubscriptionsKeys > 0 then 
		local firstKey = next(VCCSubscriptionsKeys) 
		VCCSubscriptionsKey = VCCSubscriptionsKeys[firstKey] 
	else
		return false, "No Knowledge Fusion credentials"
	end 

	return m_runtime.GenerateAnswerV2(vcc, info.question, info.metadata.knowledgebases,
		info.metadata.words_limit, info.metadata.number_of_words, VCCSubscriptionsKey.subscriptionName, 
		VCCSubscriptionsKey.subscriptionKey)
end

------------------------
-- VCCs
------------------------
--[[
]]--
function VccSupportsQnAMaker (vcc)
	assert(vcc)
	local _, total = LoadVCCSubscriptions(vcc)
	local isSupported = false
	if total > 0 then
		isSupported = true
	end
	return isSupported
end

function VccSupportsQnAMakerV2 (vcc) -- fede
	assert(vcc)
	local _, total = LoadVCCSubscriptionsV2(vcc)
	local isSupported = false
	if total > 0 then
		isSupported = true
	end
	return isSupported
end

function AddQuestionToKB (vcc, knowledgeBase, question, answer)
	assert(vcc)
	assert(knowledgeBase)
	assert(question)
	assert(answer)

	local VCCSubscriptionsKeys, totalVCCSubscriptionsKeys = LoadVCCSubscriptionsV2(vcc)

	local VCCSubscriptionsKey = {} 
	if totalVCCSubscriptionsKeys > 0 then 
		local firstKey = next(VCCSubscriptionsKeys) 
		VCCSubscriptionsKey = VCCSubscriptionsKeys[firstKey] 
	else
		return false, {}
	end 

	return m_runtime.AddQuestionToKB(vcc, knowledgeBase, question, answer, VCCSubscriptionsKey.subscriptionName, VCCSubscriptionsKey.subscriptionKey)
	
end

function ContextualizeResponse (vcc, message, model, auth_header_name, auth_header_value, domain, timeout, question)
	assert(vcc)
	assert(message)
	assert(model)
	assert(auth_header_name)
	assert(auth_header_value)
	assert(domain)
	assert(timeout)
	assert(question)

	return m_runtime.ContextualizeResponse(vcc, message, model, auth_header_name, auth_header_value, domain, timeout, question)	
end
