local json = require "json"
local request = require "qna_maker.request"

module(..., package.seeall)

local function GetBaseURI (id)
	id = id or "RUNTIME_ENDPOINT_URL"
	local api = require "qna_maker"
	return api.GetBaseURI(id)
end

function MakeAnswerPostInfo (info, hostName, resourceLocation, primaryEndpointKey)
	assert(type(info) == "table")
	assert(type(info.question) == "string")
	assert(type(info.top) == "number" or type(info.top) == "nil")
	assert(type(hostName) == "string")
	assert(type(resourceLocation) == "string")
	assert(type(primaryEndpointKey) == "string")

	local isTest = true -- TODO: Hay que obtener el valor correcto !!
	if type(info.isTest) == "boolean" then
		isTest = info.isTest
	end

	local baseURI = GetBaseURI("RUNTIME_ENDPOINT_URL")
	local data = {
		baseURI = baseURI,
		hostName = hostName,
		resourceLocation = resourceLocation,
		primaryEndpointKey = primaryEndpointKey,
		uri = string.format(baseURI, hostName, resourceLocation),
		headers = {
			["Authorization"] = "EndpointKey " .. primaryEndpointKey
		},
		postData = {
			question = info.question,
			top      = info.top or 10,
			isTest   = isTest
		}
	}

	-- metadata
	if type(info.metadata) == "table" then
		if type(info.metadata.filters) == "table" then
			data.postData.strictFilters = info.metadata.filters -- {name = "ciudad", value = "colonia"}
			assert(type(info.metadata.operationType) == "string" or type(info.metadata.operationType) == "nil")
			data.postData.strictFiltersCompoundOperationType = info.metadata.operationType or "OR" -- OR / AND
		end
	end

	return data
end

function MakeAnswerPostInfoV2 (info, hostName, resourceLocation, primaryEndpointKey) -- fede
	assert(type(info) == "table")
	assert(type(info.question) == "string")
	assert(type(info.top) == "number" or type(info.top) == "nil")
	assert(type(hostName) == "string")
	assert(type(resourceLocation) == "string")
	assert(type(primaryEndpointKey) == "string")

	local isTest = true -- TODO: Hay que obtener el valor correcto !!
	if type(info.isTest) == "boolean" then
		isTest = info.isTest
	end

	local baseURI = GetBaseURI("RUNTIME_ENDPOINT_URL_V2")
	local data = {
		baseURI = baseURI,
		hostName = hostName,
		resourceLocation = resourceLocation,
		primaryEndpointKey = primaryEndpointKey,
		uri = string.format(baseURI, hostName, resourceLocation),
		headers = {
			["Authorization"] = "EndpointKey " .. primaryEndpointKey
		},
		postData = {
			question = info.question,
			top      = info.top or 10,
			isTest   = isTest
		}
	}

	-- metadata
	if type(info.metadata) == "table" then
		if type(info.metadata.filters) == "table" then
			data.postData.strictFilters = info.metadata.filters -- {name = "ciudad", value = "colonia"}
			assert(type(info.metadata.operationType) == "string" or type(info.metadata.operationType) == "nil")
			data.postData.strictFiltersCompoundOperationType = info.metadata.operationType or "OR" -- OR / AND
		end
	end

	return data
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>", "isTest": true, top: 10, metadata={filters={{name="nombre", value="de Mello"}}, opertationType="OR"}}
]]--
function GenerateAnswer (info, hostName, resourceLocation, primaryEndpointKey, mustUseCurl)
	assert(type(info) == "table")
	assert(type(info.question) == "string")
	assert(type(hostName) == "string")
	assert(type(resourceLocation) == "string")
	assert(type(primaryEndpointKey) == "string")

	local postInfo = MakeAnswerPostInfo(info, hostName, resourceLocation, primaryEndpointKey)
	local contentType = nil
	local ocpApimSubscriptionKey = nil

	local success, response
	if mustUseCurl then
		--CURL - Usa CURL para realizar el POST request
		success, response = request.CurlPost(postInfo.uri, postInfo.postData, contentType, ocpApimSubscriptionKey, postInfo.headers)
	else
		--SSL - Usa la rocka SSL para realizar el POST request
		success, response = request.Post(postInfo.uri, postInfo.postData, contentType, ocpApimSubscriptionKey, postInfo.headers)
	end

	if not success then
		local err = response
		LogError("[QNA_MAKER_RUNTIME:GenerateAnswer] Error Generating Anwser. Question '%s' URI: '%s', postData: '%s'. Error: '%s'", info.question, postInfo.uri, json.encode(postInfo.postData), err)
		return false, err
	end

	local encodedAnswer = table.concat(response)
	local answer = json.decode(encodedAnswer)

	LogInfo("[QNA_MAKER_RUNTIME:GenerateAnswer] Success Generated Answer. Question '%s', data: '%s'", info.question, encodedAnswer)

	return true, answer
end

function GenerateAnswerV2 (vcc, question, knowledgebases, words_limit, number_of_words, subscriptionName, subscriptionKey)
	assert(type(vcc) == "string")
	assert(type(question) == "string")
	assert(type(knowledgebases) == "string")
	assert(type(subscriptionName) == "string")
	assert(type(subscriptionKey) == "string")

	--local encodedKnowledgebases = table.concat(knowledgebases)
	local knowledgebasesParsed = json.decode(knowledgebases)
	
	local kbs = {}

	for id, item in pairs(knowledgebasesParsed) do
		table.insert(kbs, item.id)
	end

	local customHeaders = {
		["apikey"] = subscriptionKey,
		["Content-Type"] = "application/json"
	}

	--https://api.backend.inconcertcc.com/qna/query/gpt?threshold=0.145&maxWords=true&words=70

	local url = "https://" .. subscriptionName .. "/qna/query/gpt?threshold=0.145"

	if words_limit == true and tonumber(number_of_words) > 0 then
		url = url .. "&maxWords=true&words=" .. number_of_words
	end

	local body = { 
		message = question,
		knowledgebases = kbs
	}
	customHeaders["Content-Length"] = tostring(#json.encode(body))

	local success, response = request.Post(url, json.encode(body), "application/json", nil, customHeaders)
	if not success then
		LogError("[QNA_RUNTIME:GenerateAnswerV2] Error getting knowledge base response: '%s'", json.encode(response))
		return false, response
	end

	local encodedResponse = table.concat(response)
	local parsedResponse = json.decode(encodedResponse)

	return success, parsedResponse.text
end

function AddQuestionToKB (vcc, knowledgeBase, question, answer, subscriptionName, subscriptionKey)
	
	local customHeaders = {
		["apikey"] = subscriptionKey,
		["Content-Type"] = "application/json"
	}

	local success, response = request.Get("https://" .. subscriptionName .. "/rasa/api/qna/knowledgebase/" .. knowledgeBase, nil, customHeaders)
	if not success then
		LogError("[QNA_RUNTIME:AddQuestionToKB] Error getting knowledge base: '%s'", json.encode(response))
		return false, response
	end

	local encodedResponse = table.concat(response)
	local parsedResponse = json.decode(encodedResponse)

	local points = {}

	if parsedResponse.versionA ~= nil and parsedResponse.versionA.active then
		points = parsedResponse.versionA.points
	else
		if parsedResponse.versionB ~= nil and parsedResponse.versionB.active then
			points = parsedResponse.versionB.points
		end
	end

	table.insert(points, {
		questions = {{ question = question }},
		answers = {{ answer = answer }}
	})

	local body = { points = points }
	customHeaders["Content-Length"] = tostring(#json.encode(body))

	success, response = request.Put("https://" .. subscriptionName .. "/rasa/api/qna/knowledgebase/" .. knowledgeBase .. "/version", 
	json.encode(body), "application/json", nil, customHeaders)

	if not success then
		LogError("[QNA_RUNTIME:AddQuestionToKB] Error updating knowledge base version: '%s'", json.encode(response))
		return false, response
	end

	body = {}
	customHeaders["Content-Length"] = tostring(#json.encode(body))

	success, response = request.Put("https://" .. subscriptionName .. "/rasa/api/qna/knowledgebase/" .. knowledgeBase .. "/active", 
	json.encode(body), "application/json", nil, customHeaders)

	if not success then
		LogError("[QNA_RUNTIME:AddQuestionToKB] Error activating knowledge base version: '%s'", json.encode(response))
		return false, response
	end

	return success, response
end

function ContextualizeResponse (vcc, message, model, auth_header_name, auth_header_value, domain, timeout, question)
	
	local messagesHistoryLocal = "[]"					
	local conversation_thread_JSON = json.decode(messagesHistoryLocal)
	
	local newMessage = { role = "assistant", content = "Enhance the following text to make it appear as if it was written by an autonomous virtual assistant. The question was: '''".. question .."'''. The answer you should decorate is: '''".. message .."'''" }
	table.insert(conversation_thread_JSON, newMessage)
	
	local body = [[
		{
		"model": "]] .. model .. [[",
		"messages": ]] .. json.encode(conversation_thread_JSON) .. [[,
		"temperature": 0.12
		}
	]]
	
	local success, response = request.Post(domain, body, "application/json", nil, { [auth_header_name] = auth_header_value })

	if not success then
		LogError("[QNA_RUNTIME:ContextualizeResponse] Error contextualizing response: '%s'", json.encode(response))
		return false, response
	end

	local encodedResponse = table.concat(response)
	local parsedResponse = json.decode(encodedResponse)
					
	if parsedResponse.choices and #parsedResponse.choices > 0 then
		local respMessage = parsedResponse.choices[1].message							
		return true, respMessage.content
	end

	return false, response

end
