local json = require "cjson"
local request = require "luis.request"

module(..., package.seeall)

local m_instanceOwner
function SetOwner (instanceOwner)
	m_instanceOwner = instanceOwner
end

local m_defaultAppVersion = "2.0" 

local function MakeCompleteURI (uriBaseId, uri, ...)
	uriBaseId = uriBaseId or "APPS"
	return m_instanceOwner:MakeCompleteURI(m_defaultAppVersion, uriBaseId, uri, ...) 
end

--[[
	Retorna los parametros:
		1) Si tiene paginado    : "?skip=0&take=2"
		2) Si no tiene paginado : ""
]]--
local function MakePagingParameters (params)
	local api = require "luis"
	return api.MakePagingParameters(params)
end

-- *******************************************************************************
-- API INTENTS
-- *******************************************************************************

--[[
-----------------------------
MODELS - GET APPLICATION VERSION INTENT INFOS
-----------------------------
	Gets information about the intent models.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents[?skip][&take]

	Request parameters
	------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		skip (optional) integer The number of entries to skip. Default value is 0.

		take (optional) integer The number of entries to return. Maximum page size is 500. Default is 100.

	Request headers
	------------
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.
		Request body

	Request body
	------------

	Response 200
	------------
		A list of intent model infos.
			[
			  {
				"id": "227a71ed-7d4b-4dce-8f3a-16c4e5cc06e8",
				"name": "BookFlight",
				"typeId": 0,
				"readableType": "Intent Classifier"
			  },
			  {
				"id": "8285a9ee-6bc0-4409-87f4-82d539f70529",
				"name": "None",
				"typeId": 0,
				"readableType": "Intent Classifier"
			  },
			  {
				"id": "9500536f-ffec-4fab-93ad-6268abb0f73c",
				"name": "$Camera.CapturePhoto",
				"typeId": 0,
				"readableType": "Intent Classifier",
				"customPrebuiltDomainName": "Camera",
				"customPrebuiltModelName": "CapturePhoto"
			  },
			]

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c0d
]]--
function LoadAllAppIntents (appId, versionId, paginated)
	assert(appId)
	assert(versionId)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents", appId, versionId)
	uri = uri .. MakePagingParameters(paginated)

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_INTENTS:LoadAllAppIntents] Error loading all APP INTENTS on appId '%s' versionId: '%s'. Error: '%s'", appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:LoadAllAppIntents] Success loaded all APP INTENTS on appId '%s' versionId: '%s'.", appId, versionId)

	local encodedIntents = table.concat(response)
	return true, encodedIntents
end

--[[
-----------------------------
MODELS - GET INTENT INFO
-----------------------------
	Gets information about the intent model.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents/{intentId}

	Request parameters
	------------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		intentId string Format - guid. The intent classifier ID.

	Request headers
	----------------
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.


	Request body
	------------

	Response 200
	-------------
		An intent model info.
			{
				"id": "8285a9ee-6bc0-4409-87f4-82d539f70529",
				"name": "None",
				"typeId": 0,
				"readableType": "Intent Classifier"
			}

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c1a
]]--
function GetAppIntent (appId, intentId, versionId)
	assert(appId)
	assert(intentId)
	assert(versionId)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents/%s", appId, versionId, intentId)

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_INTENTS:GetAppIntent] Error getting APP INTENTS '%s' on appId '%s' versionId: '%s'. Error: '%s'", intentId, appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:GetAppIntent] Success get APP INTENTS '%s' on appId '%s' versionId: '%s'.", intentId, appId, versionId)

	local encodedIntent = table.concat(response)
	return true, encodedIntent
end

--[[
-----------------------------
MODELS - CREATE INTENT CLASSIFIER
-----------------------------
	Adds an intent classifier to the application.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents

	Request parameters
	------------
		appId string Format - guid. ID of the application.

		versionId string The task version ID.

	Request headers
	------------
		Content-Type (optional) string Media type of the body sent to the API.
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		A model object containing the name of the new intent classifier.

		application/json
		Sample:
			{
				"name": "BookFlight"
			}

	Response 201
	------------
		The ID of the created model.

		"227a71ed-7d4b-4dce-8f3a-16c4e5cc06e8"

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c0c
]]--
function CreateAppIntent (info)
	assert(type(info) == "table")
	assert(info.appId)
	assert(info.versionId)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents", info.appId, info.versionId)

	local data = {
		name = info.name
	}
	local success, response = request.Post(uri, data)
	if not success then
		LogError("[LUIS_INTENTS:CreateAppIntent] Error creating APP INTENTS on appId '%s' versionId: '%s'. Response: '%s'", info.appId, info.versionId, json.encode(response))
		return false, response
	end

	local intentId = table.concat(response)
	LogInfo("[LUIS_INTENTS:CreateAppIntent] Success created APP INTENTS on appId '%s' versionId: '%s', intentId: '%s'.", info.appId, info.versionId, intentId)

	return true, intentId
end

--[[
-----------------------------
MODELS - RENAME INTENT MODEL
-----------------------------
	Updates the name of an intent classifier.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents/{intentId}

	Request parameters
	------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		intentId string Format - guid. The intent classifier ID.

	Request headers
	------------
		Content-Type (optional) string Media type of the body sent to the API.
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		A model object containing the new intent classifier name.

		application/json

		Sample:
			{
				"name": "BookingFlight"
			}

	Response 200
	------------
		Empty response

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c1b
]]--
function RenameAppIntent (info)
	assert(info)
	assert(info.appId)
	assert(info.intentId)
	assert(info.versionId)
	assert(info.name)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents/%s", info.appId, info.versionId, info.intentId)

	local data = {
		---- Requerido
		name = info.name
	}
	local success, response = request.Put(uri, data)
	if not success then
		LogError("[LUIS_INTENTS:RenameAppIntent] Error renaming APP INTENTS '%s' on appId '%s' versionId: '%s'. Response: '%s'", info.intentId, info.appId, info.versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:RenameAppIntent] Success renamed APP INTENTS '%s' on appId '%s' versionId: '%s'.", info.intentId, info.appId, info.versionId)

	return true, response
end

--[[
-----------------------------
MODELS - DELETE INTENT MODEL
------------------------------
	Deletes an intent classifier from the application.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents/{intentId}

	Request parameters
	------------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		intentId string Format - guid. The intent classifier ID.

	Request headers
	-----------------
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		...

	Response 200
	------------
		Empty response

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c1c
]]--
function DeleteAppIntent (appId, intentId, versionId)
	assert(appId)
	assert(intentId)
	assert(versionId)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents/%s", appId, versionId, intentId)

	local success, response = request.Delete(uri)
	if not success then
		LogError("[LUIS_INTENTS:DeleteAppIntent] Error deleting APP INTENTS '%s' on appId '%s' versionId: '%s'. Response: '%s'", intentId, appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:DeleteAppIntent] Success deleted APP INTENTS '%s' on appId '%s' versionId: '%s'.", intentId, appId, versionId)

	return true, response
end

--[[
-----------------------------
EXAMPLES - REVIEW LABELED EXAMPLES
-----------------------------
	Returns examples to be reviewed.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/examples[?skip][&take]

	Request parameters
	------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		skip (optional) integer The number of entries to skip. Default value is 0.

		take (optional) integer The number of entries to return. Maximum page size is 500. Default is 100.

	Request headers
	------------
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		...

	Response 200
	------------
		A list of predictions and label pairs for every example in the application.
			[
			  {
				"id": -12,
				"text": "what's the weather like in seattle?",
				"tokenizedText": [
				  "what",
				  "'",
				  "s",
				  "the",
				  "weather",
				  "like",
				  "in",
				  "seattle",
				  "?"
				],
				"intentLabel": "GetWeather",
				"entityLabels": [
				  {
					"entityName": "Location",
					"startTokenIndex": 7,
					"endTokenIndex": 7
				  }
				],
				"intentPredictions": [
				  {
					"name": "GetWeather",
					"score": 1
				  },
				  {
					"name": "None",
					"score": 0.21
				  },
				  {
					"name": "BookFlight",
					"score": 0
				  }
				],
				"entityPredictions": [
				  {
					"entityName": "Location",
					"startIndex": 7,
					"endIndex": 7,
					"phrase": "seattle"
				  }
				]
			  },
			  ..
			]
	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c0a
]]--
function LoadPagingUtterancesForApp (appId, versionId, paginated)
	assert(appId)
	assert(versionId)
	assert(paginated)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/examples", appId, versionId)
	uri = uri .. MakePagingParameters(paginated)

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_INTENTS:LoadPagingUtterancesForApp] Error loading APP UTTERANCES on appId '%s' versionId: '%s'. Error: '%s'", appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:LoadPagingUtterancesForApp] Success loaded APP UTTERANCES on appId '%s' versionId: '%s', paginated: %s.", appId, versionId, json.encode(paginated))

	local encodedUtterances = table.concat(response)
	return true, encodedUtterances
end

--[[
-----------------------------
EXAMPLES - ADD LABEL
-----------------------------
	Adds a labeled example to the application.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/example

	Request parameters
	------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

	Request headers
	------------
		Content-Type (optional) string Media type of the body sent to the API.
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		A JSON object containing the example label.

		application/json
		Sample:
			{
				"text": "Book me a flight from Cairo to Redmond next Thursday",
				"intentName": "BookFlight",
				"entityLabels":
				[
					{
						"entityName": "Location::From",
						"startCharIndex": 22,
						"endCharIndex": 26
					},
					{
						"entityName": "Location::To",
						"startCharIndex": 31,
						"endCharIndex": 37
					}
				]
			}

	Response 201
	------------
		The ID of the created example.
			{
				"UtteranceText": "book me a flight from cairo to redmond next thursday",
				"ExampleId": -11
			}

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c08
]]--
function AddUtteranceAppIntent (info)
	assert(type(info) == "table")
	assert(info.appId)
	assert(info.versionId)
	assert(info.intentName)
	assert(info.utterance)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/example", info.appId, info.versionId)

	-- Requeridos
	local data = {text = info.utterance, intentName = info.intentName}
	-- Opcional
	if type(info.entityLabels) == "table" then
		data.entityLabels = {}
		for _, lbl in pairs(info.entityLabels) do
			table.insert(data.entityLabels, {
				entityName     = lbl.entityName,
				startCharIndex = lbl.startCharIndex,
				endCharIndex   = lbl.endCharIndex
			})
		end
	end

	local success, response = request.Post(uri, data)
	if not success then
		LogError("[LUIS_INTENTS:AddUtteranceAppIntent] Error Adding UTTERANCE TO INTENT '%s' on appId '%s' versionId: '%s'. Utterance: '%s'. Response: '%s'", info.intentName, info.appId, info.versionId, info.utterance, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:AddUtteranceAppIntent] Success Adding UTTERANCE TO INTENT '%s' on appId '%s' versionId: '%s'. Utterance: '%s'.", info.intentName, info.appId, info.versionId, info.utterance)

	return true, response
end

--[[
-----------------------------
EXAMPLES - DELETE EXAMPLE LABELS
-----------------------------
	Deletes the label with the specified ID.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/examples/{exampleId}

	Request parameters
	------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		exampleId integer The example ID.

	Request headers
	------------
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		...
	Response 200
	------------

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c0b
]]--
function DeleteAppUtterance (appId, utteranceId, versionId)
	assert(appId)
	assert(utteranceId)
	assert(versionId)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/examples/%s", appId, versionId, utteranceId)

	local success, response = request.Delete(uri)
	if not success then
		LogError("[LUIS_INTENTS:DeleteAppUtterance] Error deleting UTTERANCE '%s' on appId '%s' versionId: '%s'. Response: '%s'", utteranceId, appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:DeleteAppUtterance] Success deleted UTTERANCE '%s' on appId '%s' versionId: '%s'.", utteranceId, appId, versionId)

	return true, response
end

--[[
-----------------------------
MODELS - SUGGEST ENDPOINT QUERIES FOR INTENTS
-----------------------------
	Suggests examples that would improve the accuracy of the intent model.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/versions/{versionId}/intents/{intentId}/suggest[?take]

	Request parameters
	------------
		appId string Format - guid. The application ID.

		versionId string The task version ID.

		intentId string Format - guid. The target intent classifier model to enhance.

		take (optional) integer Maximum number of queries to be returned. Default is set to 10. Maximum is 500.

	Request headers
	------------
		Ocp-Apim-Subscription-Key string Subscription key which provides access to this API. Found in your Cognitive Services accounts.

	Request body
	------------
		...

	Response 200
	------------
		If there's no trained model, nothing is returned in the response.
		If there's a trained model and the active learning algorithm finds any relevant queries, they are returned with the model predictions.
		If there's a trained model but the active learning algorithm didn't find any relevant queries, an empty list is returned in the response.

			[
				{
					"text": "hello, world!",
					"tokenizedText": [
						"hello",
						",",
						"world",
						"!"
					],
					"intentPredictions": [
						{
							"name": "None",
							"score": 0.63
						},
						{
							"name": "GetWeather",
							"score": 0
						},
						{
							"name": "BookFlight",
							"score": 0
						}
					],
					"entityPredictions": []
				}
			]

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c2d
]]--
function LoadSuggestedUtterancesByAppIntent (appId, versionId, intentId)
	assert(appId)
	assert(versionId)
	assert(intentId)


	local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents/%s/suggest?take=500", appId, versionId, intentId)
	--uri = uri .. MakePagingParameters(paginated) -- TODO: Implementar simple paginado si es necesario (solo take)

	--[[
		Pruebas
		-------
			multiple-intents=true  a este atributo asi lo tiran microsoft en los request de su interfaz. El mismo es un atributo NO documentado.
			Lo que hace es traer unicamente los suggestedd que pertenzcan al intent.

		--local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents/%s/suggest?multiple-intents=true", appId, versionId, intentId)

			Prueba mia para traer 20
		--local uri = MakeCompleteURI("APPS", "%s/versions/%s/intents/%s/suggest?take=20", appId, versionId, intentId)

	]]--
	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_INTENTS:LoadSuggestedUtterancesByAppIntent] Error loading APP SUGGESTED UTTERANCES on appId '%s' versionId: '%s'. Error: '%s'", appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_INTENTS:LoadSuggestedUtterancesByAppIntent] Success loaded APP SUGGESTED UTTERANCES on appId '%s' versionId: '%s'.", appId, versionId)


	local encodedUtterances = table.concat(response)
--[[
	-- Si queremos loguer los suggested hay que descomentar las siguiente lineas.

	local logDestination = {}
	local suggestedUtterances = json.decode(encodedUtterances)
	for _, utterance in ipairs(suggestedUtterances) do
		table.insert(logDestination, utterance.text)
	end
	LogDebug("[LUIS_INTENTS:LoadSuggestedUtterancesByAppIntent] Success loaded APP SUGGESTED UTTERANCES on appId '%s' versionId: '%s',\n Suggested Utterances: %s.", appId, versionId, json.encode(logDestination))
]]--
	return true, encodedUtterances
end
