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

module(..., package.seeall)

local m_instanceOwner
function SetOwner (instanceOwner)
	m_instanceOwner = instanceOwner
end

local m_defaultAppVersion = "3.0-PREVIEW" 

local function GetBaseURI (id)
	id = id or "APPS"
	return m_instanceOwner:GetBaseURI(id)
end

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 APPS
-- *******************************************************************************

--[[
-----------------------------
APPS - GET APPLICATION INFO
-----------------------------
	Gets the application info.

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

	Request parameters
	------------
		appId string Format - guid. The application 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
	------------
		A JSON object containing the application info.

		{
		  "id": "363187f1-c573-46b3-bc4c-ae01d686e68e",
		  "name": "MyFirstDummyAp",
		  "description": "This is my first dummy application",
		  "culture": "en-us",
		  "usageScenario": "IoT",
		  "domain": "Comics",
		  "versionsCount": 3,
		  "createdDateTime": "2017-01-31T16:15:54Z",
		  "endpoints": {
			"PRODUCTION": {
			  "versionId": "0.1",
			  "isStaging": false,
			  "endpointUrl": "DummyUrl",
			  "endpointRegion":"westus",
			  "assignedEndpointKey": "",
			  "publishedDateTime": "2017-02-19T17:09:14Z"
			}
		  },
		  "endpointHitsCount": 0
		}

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c37
]]--
function Get (appId)
	assert(appId)

	local uri = MakeCompleteURI("APPS", "%s", appId)

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_APPS:Get] Get App '%s' Error: '%s'", appId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:Get] Success Get App %s.", appId)
	local encodedApp = table.concat(response)

	--LogDebug("[LUIS_APPS:Get] App: appId: '%s', data: '%s'", appId, encodedApp)
	return true, encodedApp
end

--[[
-----------------------------
APPS - ADD APP
-----------------------------
	Creats a new application

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/

	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 Name, Description (optional), Culture, Usage Scenario (optional), Domain (optional) and initial version ID (optional) of the application. Default value for the version ID is 0.1.

		application/json

		Sample:
			{
				"name": "MyFirstDummyApp",
				"description": "This is my first dummy application",
				"culture": "en-us",
				"usageScenario": "IoT",
				"domain": "Comics",
				"initialVersionId": "1.0"
			}

	Response 200
	------------
		The ID of the newly created application

		"363187f1-c573-46b3-bc4c-ae01d686e68e"

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c2f
]]--
function Add (info)
	assert(type(info) == "table")
	assert(type(info.name) == "string")
	assert(type(info.culture) == "string")

	local uri = GetBaseURI()
	local data = {
		---- Requerido
		id               = info.name,
		name             = info.__occName or info.name,
		culture          = info.culture,
		---- Opcionales
		description      = info.__occDescription or info.description,
		usageScenario    = info.usageScenario,
		domain           = info.domain,
		initialVersionId = info.initialVersionId
	}

	local success, response = request.Post(uri, data)
	if not success then
		LogError("[LUIS_APPS:Add] Adding App Error: '%s'", json.encode(response))
		return false, response
	end

	local appId = table.concat(response)
	LogInfo("[LUIS_APPS:Add] Success added appId %s.", appId)

	return true, appId
end

--[[
-----------------------------
APPS - RENAME APPLICATION
-----------------------------
	Updates the name or description of the application.

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

	Request parameters
	------------
		appId string Format - guid. The application 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 Name and Description of the application.

		application/json

		Sample:
			{
				"name": "MyFirstRenamedDummyAp",
				"description": "This is my first modified dummy description"
			}

	Response 200
	------------
		null

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c38
]]--
function Rename (info)
	assert(type(info) == "table")
	assert(type(info.id) == "string")
	assert(type(info.name) == "string")

	local uri = MakeCompleteURI("APPS", "%s", info.id)

	local appData = {
		-- Requerido
		name        = info.__occName or info.name,
		-- Opcional
		description = info.__occDescription or info.description,
	}
	local success, response = request.Put(uri, appData)
	if not success then
		LogError("[LUIS_APPS:Rename] Renaming App '%s' Error: '%s'", info.id, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:Rename] Success Renamed appId %s.", info.id)

	return true, response
end

--[[
-----------------------------
APPS - DELETE APPLICATION
-----------------------------
	Open API testing console

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

	Request parameters
	------------
		appId string Format - guid. The application 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
	------------
		null

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c39
]]--
function Delete (appId)
	assert(appId)

	local uri = MakeCompleteURI("APPS", "%s", appId)

	local success, response = request.Delete(uri)
	if not success then
		--[[
			En el caso de que la Aplicación haya sido eliminada por fuera de INCONCERT, es decir que se haya eliminada desde la GUI de LUIS,
			el API de LUIS va retornar el código de error 400, y la descripción del porqué ha fallado.
			Como este código de error 400 puede llegar en diferentes tipos de error, hay que validar contra el código de error + la descripción del error.
			En el caso de que efectivamente la App haya sido eliminada por fuera de INCONCERT, debemos retornar un código success, para que la función que ha invocado a la función actual, elimine de Cassandra el registro correspondiente a la APP.
		]]--
		if response and tostring(response.code) == "400" and (response.response and response.response.error) then
			local luisErrorMessage = (response.response.error.message or ""):lower()
			--LogDebug("[LUIS_APPS:Delete] 1 - luisErrorMessage: '%s'", luisErrorMessage)
			local cannotFindError = ("Cannot find an application with the ID %s."):format(appId):lower()
			--LogDebug("[LUIS_APPS:Delete] 2 - cannotFindError: '%s'", cannotFindError)
			if cannotFindError == luisErrorMessage then
				LogInfo("[LUIS_APPS:Delete] Application '%s' does not exist in the LUIS Database. Response: '%s'.", appId, json.encode(response))
				success = true
				-- Este el JSON que retorna el API de LUIS, cuando se ha eliminado correctamente la APP.
				-- Lo que hacemos acá, es retornar el mismo JSON hacia la función que me ha invocado, para que esta proceda.
				response = {code = "Success", message = "Operation Successful"}
				return true, response
			end
		end
		LogError("[LUIS_APPS:Delete] Deleting App '%s' Error: '%s'", appId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:Delete] Success deleted app %s.", appId)

	--LogDebug("[LUIS_APPS:Delete] response: '%s'", json.encode(response))
	return true, response
end

--[[
-----------------------------
APPS - GET APPLICATION CULTURES
-----------------------------
	Gets the supported application cultures.

	Request URL
	------------
		https://westus.api.cognitive.microsoft.com/luis/api/v2.0/apps/cultures

	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 object containing the supported application cultures.
			[
				{
					"name": "English",
					"code": "en-us"
				},
				{
					"name": "Chinese",
					"code": "zh-cn"
				},
				..
				..
			]

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c35
]]--
function LoadAppCultures ()

	local uri = MakeCompleteURI("APPS", "cultures")

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_APPS:LoadAppCultures] Loading Application Cultures. Error: '%s'", json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:LoadAppCultures] Success Loaded Application Cultures.")

	local encodedCultures = table.concat(response)

	--LogDebug("[LUIS_APPS:LoadAppCultures] Loaded Application Cultures, data: '%s'", encodedCultures)
	return true, encodedCultures
end


--[[
-----------------------------
APPS - PUBLISH APPLICATION
-----------------------------
	Publishes a specific version of the application.

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

	Request parameters
	------------
		appId string Format - guid. The application 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
	------------
		application/json
		Sample:
			{
				"versionId": "0.1",
				"isStaging": false
			}

	Response 201
	------------
		An object containing the publish date, the endpoint URL and the user's subscription key
			{
				"endpointUrl": "DummyUrl",
				"subscription-key": "DummyEndpointKey",
				"endpointRegion": "westus",
				"isStaging": false
			}

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

	local uri = MakeCompleteURI("APPS", "%s/publish", appId)

	local publishInfo = {
		versionId = info.versionId,
		isStaging = info.isStaging or false
	}

	local success, response = request.Post(uri, publishInfo)
	if not success then
		LogError("[LUIS_APPS:PublishApp] Error Publish App '%s' versionId '%s'. Error: '%s'", appId, info.versionId, json.encode(response))
		return false, response
	end

	local publishResponse = table.concat(response)
	LogInfo("[LUIS_APPS:PublishApp] Success Publish appId '%s' versionId '%s'. Response", appId, info.versionId)

	--LogDebug("[LUIS_APPS:PublishApp] ----> Publish: '%s'", publishResponse)
	return true, publishResponse
end

--[[
-----------------------------
TRAIN - GET APPLICATION VERSION TRAINING STATUS
-----------------------------
Gets the training status of all models for the specified application.

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

	Request parameters
	------------
		appId string Format - guid. The application version 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
	------------
		[
			{
				"modelId": "f9b00d5b-1f2d-421e-bc99-5ff192d0b998",
				"details": {
					"statusId": 3,
					"status": "InProgress",
					"exampleCount": 0
				}
			},
			{
				"modelId": "51403af3-5342-4926-abaa-91172a42e075",
				"details": {
				"statusId": 2,
					"status": "UpToDate",
					"exampleCount": 12,
					"trainingDateTime": "2017-01-31T21:42:02Z"
				}
			},
			{
				"modelId": "b4cf6402-dc79-4ca3-8666-b0007337e92b",
				"details": {
					"statusId": 1,
					"status": "Fail",
					"exampleCount": 12,
					"failureReason": "FewLabels"
				}
			},
			{
				"modelId": "e8e3135a-acd9-4164-a65c-e2fedbe78cfa",
				"details": {
					"statusId": 3,
					"status": "InProgress",
					"exampleCount": 0
				}
			},
			{
				"modelId": "3291fac9-6368-4c87-9562-e78cae0fa7c6",
				"details": {
					"statusId": 0,
					"status": "Success",
					"exampleCount": 12,
					"trainingDateTime": "2017-01-31T21:42:02Z"
				}
			},
			{
				"modelId": "a193efac-ab02-49d7-b005-ee717d45c4f1",
				"details": {
					"statusId": 3,
					"status": "InProgress",
					"exampleCount": 0
				}
			}
		]

	Response 200
	------------
		An array of model training status details.

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c46

	**********************************************
	ATENCION!!!
	-----------
		Esta Request/Funcion NO debe invocarse, sin que previamente se haya realizado un TRAIN (POST) de la APP.
		Ya que sino los scores de los utterances NO cambian.
		Ref #8900

			train - Get version training status
			Gets the training status of all models (intents and entities) for the specified LUIS app. You must call the train API to train the LUIS app before you call this API to get training status.

			Select the testing console in the region where you created your resource:
	**********************************************
]]--
function GetTrainApp (appId, versionId)
	assert(appId)
	assert(versionId)

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

	local success, response = request.Get(uri)
	if not success then
		LogWarning("[LUIS_APPS:GetTrainApp] Error retrieving TRAIN app '%s' versionId: '%s'. Error: '%s'", appId, versionId, json.encode(response))
		return false, response
	end

	local encodedSubscription = table.concat(response)

	LogInfo("[LUIS_APPS:GetTrainApp] Success retrieving TRAIN app '%s' versionId: '%s'. Subscription Info: %s", appId, versionId, encodedSubscription)

	return true, encodedSubscription
end

--[[
-----------------------------
TRAIN - TRAIN APPLICATION VERSION
-----------------------------
Sends a training request for the models of the specified application version.
The application version is not considered trained unless all the models either have been trained successfully or are up to date.
The user must get the training status at least once after training is completed.

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

	Request parameters
	------------
		appId string Format - guid. The application version 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
	------------


	Response 200
	------------


	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c45

]]--
function TrainApp (info)
	assert(type(info) == "table")
	assert(info.appId)
	assert(info.versionId)

	local uri = MakeCompleteURI("APPS", "%s/versions/%s/train", info.appId, info.versionId)
	local data = {}

	local success, response = request.Post(uri, data)
	if not success then
		LogError("[LUIS_APPS:TrainApp] Error TRAINING app '%s' versionId: '%s'. Error: '%s'", info.appId, info.versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:TrainApp] Success TRAINING app '%s' versionId: '%s'. Response: '%s'", info.appId, info.versionId, json.encode(response))

	return true, response
end

--[[
-----------------------------
VERSIONS - GET APPLICATION VERSION
-----------------------------

Gets the task info.

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

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

		versionId string The task version ID.

	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 JSON object containing the task info.

		{
			"version": "0.1",
			"createdDateTime": "2017-01-31T16:38:06Z",
			"lastModifiedDateTime": "2017-01-31T18:04:35Z",
			"lastTrainedDateTime": "2017-01-31T17:05:25Z",
			"lastPublishedDateTime": "2017-01-31T17:05:37Z",
			"endpointUrl": "DummyUrl",
				"assignedEndpointKey": {
				"SubscriptionKey": "",
				"SubscriptionName": ""
			},
			"externalApiKeys": {},
			"intentsCount": 3,
			"entitiesCount": 2,
			"endpointHitsCount": 0
		}

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c3d

]]--
function GetAppVersion (appId, versionId)
	assert(appId)
	assert(versionId)

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

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_APPS:GetAppVersion] Error retrieving 'Application Version'. App '%s' versionId: '%s'. Error: '%s'", appId, versionId, json.encode(response))
		return false, response
	end

	local encodedVersion = table.concat(response)

	LogInfo("[LUIS_APPS:GetAppVersion] Success retrieving 'Application Version'. app '%s' versionId: '%s'. Version Info: %s", appId, versionId, encodedVersion)

	return true, encodedVersion
end

--[[
-----------------------------
VERSIONS - GET APPLICATION VERSIONS
-----------------------------
	Gets the application versions info.

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

	Request parameters
	------------
		appId string Format - guid. The application 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 JSON object containing the tasks info.
			[
				{
					"version": "0.1",
					"createdDateTime": "2017-01-31T16:38:06Z",
					"lastModifiedDateTime": "2017-01-31T18:04:35Z",
					"lastTrainedDateTime": "2017-01-31T17:05:25Z",
					"lastPublishedDateTime": "2017-01-31T17:05:37Z",
					"endpointUrl": "DummyUrl",
					"assignedEndpointKey": {
						"SubscriptionKey": "",
						"SubscriptionName": ""
					},
					"externalApiKeys": {},
					"intentsCount": 3,
					"entitiesCount": 2,
					"endpointHitsCount": 0
				},
				{
					"version": "0.2",
					"createdDateTime": "2017-01-31T19:10:29Z",
					"lastModifiedDateTime": "2017-01-31T19:12:47Z",
					"lastTrainedDateTime": "2017-01-31T19:13:00Z",
					"lastPublishedDateTime": "2017-01-31T19:13:20Z",
					"endpointUrl": "DummyUrl",
					"assignedEndpointKey": {
						"SubscriptionKey": "",
						"SubscriptionName": ""
					},
					"externalApiKeys": {},
					"intentsCount": 3,
					"entitiesCount": 2,
					"endpointHitsCount": 0
				}
			]

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

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

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

	LogInfo("[LUIS_APPS:LoadAppVersions] Success loaded APPLICATION VERSIONS on appId '%s' versionId: '%s'.", appId, versionId)

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

--[[
-----------------------------
VERSIONS - EXPORT APPLICATION VERSION
-----------------------------

    Exports a LUIS application to JSON format.

	Request URL
	------------
		https://{endpoint}/luis/authoring/v3.0-preview/apps/{appId}/versions/{versionId}/export[?format]

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

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

		format (optional)string Export format type.

	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
	------------
        The JSON string of the exported application.

        {"luis_schema_version":"3.2.0","versionId":"0.2","name":"LUIS travel app","desc":"","culture":"en-us","tokenizerVersion":"1.0.0","intents":[{"name":"BookFlight"},{"name":"None"},{"name":"OrderFood"},{"name":"Weather.GetForecast","inherits":{"domain_name":"Weather","model_name":"GetForecast"}}],"entities":[{"name":"Airline","roles":["role1","role2"]},{"name":"DrinkSize","roles":[]},{"name":"Location","children":["LocationFrom","LocationTo"],"roles":[]},{"name":"PassengerCategory","children":["infant","child","adult"],"roles":[]},{"name":"TravelClass","children":["first","economy","business"],"roles":[]}],"composites":[{"name":"TicketsOrder","children":["PassengerCategory","TravelClass","number"],"roles":[]}],"closedLists":[{"name":"Coastal Cities","subLists":[{"canonicalForm":"Barcelona","list":["capital city of catalonia","bcn","second spanish city"]},{"canonicalForm":"madrid","list":["mad"]}],"roles":[]}],"patternAnyEntities":[{"name":"patternAny1","explicitList":[],"roles":["role3","role4"]},{"name":"patternAny2","explicitList":["test1","test2"],"roles":[]}],"regex_entities":[{"name":"regex1","regexPattern":"[^a]+","roles":["role5","role6"]},{"name":"regex2","regexPattern":"[^b]+","roles":[]}],"prebuiltEntities":[{"name":"datetimeV2","roles":["role7"]},{"name":"number","roles":[]}],"model_features":[],"regex_features":[],"patterns":[{"pattern":"this is a {datetimeV2:role7}","intent":"None"},{"pattern":"this is a {regex1:role5}","intent":"None"},{"pattern":"this is a {Airline}","intent":"None"}],"utterances":[{"text":"drive me home","intent":"None","entities":[]},{"text":"go to paris","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":6,"endPos":10}]},{"text":"will it snow today","intent":"Weather.GetForecast","entities":[]},{"text":"will it rain this weekend","intent":"Weather.GetForecast","entities":[]},{"text":"book me a flight to paris","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":20,"endPos":24}]},{"text":"i want to order lunch","intent":"OrderFood","entities":[]},{"text":"fly to cairo","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":7,"endPos":11}]},{"text":"flight to seattle","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":10,"endPos":16}]},{"text":"book me 2 adult business tickets to paris tomorrow on air france","intent":"BookFlight","entities":[{"entity":"TicketsOrder","startPos":8,"endPos":23},{"entity":"PassengerCategory","startPos":10,"endPos":14},{"entity":"TravelClass","startPos":16,"endPos":23},{"entity":"Location::LocationTo","startPos":36,"endPos":40},{"entity":"Airline","startPos":54,"endPos":63}]},{"text":"ticket to paris","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":10,"endPos":14}]},{"text":"what is the weather in redmond ?","intent":"Weather.GetForecast","entities":[]},{"text":"soliciting today's weather","intent":"Weather.GetForecast","entities":[]},{"text":"forecast in celcius","intent":"Weather.GetForecast","entities":[]},{"text":"will it be raining in ranchi","intent":"Weather.GetForecast","entities":[]},{"text":"provide me by toronto weather please","intent":"Weather.GetForecast","entities":[]},{"text":"\"i need to know the temperature at bangor, me\"","intent":"Weather.GetForecast","entities":[]},{"text":"get the forcast for me","intent":"Weather.GetForecast","entities":[]},{"text":"find out tomorrow's weather","intent":"Weather.GetForecast","entities":[]},{"text":"book a flight from seattle to hong kong","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":30,"endPos":38},{"entity":"Location::LocationFrom","startPos":19,"endPos":25}]},{"text":"buy a plane ticket to bangor me","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":22,"endPos":30}]},{"text":"reservation for new york city","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":25,"endPos":28},{"entity":"Location","startPos":16,"endPos":23}]},{"text":"ticket to portland","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":10,"endPos":17}]}],"settings":[{"name":"NormalizeDiacritics","value":"false"},{"name":"NormalizePunctuation","value":"false"}]}

    Response 429
	------------
       Rate limit is exceeded.

    Response 400
	------------
      This error can be returned if the request's parameters are incorrect meaning the required parameters are missing, malformed, or too large.

    Response 401
	------------
        You do not have access.

        Reasons can include:

        used endpoint subscription key, instead of authoring key
        invalid, malformed, or empty authoring key
        authoring key doesn't match region
        you are not the owner or collaborator
        invalid order of API calls
        Response 403
        Total monthly key quota limit exceeded

    Referencia:
        https://westus.dev.cognitive.microsoft.com/docs/services/luis-programmatic-apis-v3-0-preview/operations/5890b47c39e2bb052c5b9c40
]]--
function ExportApp (appId, versionId, exportFormat)
	assert(appId)

    local uri = MakeCompleteURI("APPS", "%s/versions/%s/export", appId, versionId)
    if exportFormat then
        uri = uri .. "?" .. exportFormat
    end
    exportFormat = exportFormat or "json"

	local success, response = request.Get(uri)
	if not success then
		LogError("[LUIS_APPS:ExportApp] Error exporting APPLICATION VERSIONS on appId '%s' versionId: '%s', format: '%s'. Error: '%s'", appId, versionId, exportFormat, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:ExportApp] Success Exporting APPLICATION VERSIONS on appId '%s' versionId: '%s' format: '%s'.", appId, versionId, exportFormat)

	local encodedExportedApp = table.concat(response)
	local exportedApp = json.decode(encodedExportedApp)
	return true, encodedExportedApp, exportedApp
end

--[[
-----------------------------
APPLICATIONS - IMPORT APPLICATION
-----------------------------

    Import a LUIS application from JSON format.

	Request URL
	------------
		https://{endpoint}/luis/api/v2.0/apps/import[?appName]

	Request parameters
	------------
		appName (optional)string	The imported application name.

	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
	------------
		A JSON representing the LUIS application structure.
		{"luis_schema_version":"3.2.0","versionId":"0.2","name":"LUIS travel app","desc":"","culture":"en-us","tokenizerVersion":"1.0.0","intents":[{"name":"BookFlight"},{"name":"None"},{"name":"OrderFood"},{"name":"Weather.GetForecast","inherits":{"domain_name":"Weather","model_name":"GetForecast"}}],"entities":[{"name":"Airline","roles":["role1","role2"]},{"name":"DrinkSize","roles":[]},{"name":"Location","children":["LocationFrom","LocationTo"],"roles":[]},{"name":"PassengerCategory","children":["infant","child","adult"],"roles":[]},{"name":"TravelClass","children":["first","economy","business"],"roles":[]}],"composites":[{"name":"TicketsOrder","children":["PassengerCategory","TravelClass","number"],"roles":[]}],"closedLists":[{"name":"Coastal Cities","subLists":[{"canonicalForm":"Barcelona","list":["capital city of catalonia","bcn","second spanish city"]},{"canonicalForm":"madrid","list":["mad"]}],"roles":[]}],"patternAnyEntities":[{"name":"patternAny1","explicitList":[],"roles":["role3","role4"]},{"name":"patternAny2","explicitList":["test1","test2"],"roles":[]}],"regex_entities":[{"name":"regex1","regexPattern":"[^a]+","roles":["role5","role6"]},{"name":"regex2","regexPattern":"[^b]+","roles":[]}],"prebuiltEntities":[{"name":"datetimeV2","roles":["role7"]},{"name":"number","roles":[]}],"model_features":[],"regex_features":[],"patterns":[{"pattern":"this is a {datetimeV2:role7}","intent":"None"},{"pattern":"this is a {regex1:role5}","intent":"None"},{"pattern":"this is a {Airline}","intent":"None"}],"utterances":[{"text":"drive me home","intent":"None","entities":[]},{"text":"go to paris","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":6,"endPos":10}]},{"text":"will it snow today","intent":"Weather.GetForecast","entities":[]},{"text":"will it rain this weekend","intent":"Weather.GetForecast","entities":[]},{"text":"book me a flight to paris","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":20,"endPos":24}]},{"text":"i want to order lunch","intent":"OrderFood","entities":[]},{"text":"fly to cairo","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":7,"endPos":11}]},{"text":"flight to seattle","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":10,"endPos":16}]},{"text":"book me 2 adult business tickets to paris tomorrow on air france","intent":"BookFlight","entities":[{"entity":"TicketsOrder","startPos":8,"endPos":23},{"entity":"PassengerCategory","startPos":10,"endPos":14},{"entity":"TravelClass","startPos":16,"endPos":23},{"entity":"Location::LocationTo","startPos":36,"endPos":40},{"entity":"Airline","startPos":54,"endPos":63}]},{"text":"ticket to paris","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":10,"endPos":14}]},{"text":"what is the weather in redmond ?","intent":"Weather.GetForecast","entities":[]},{"text":"soliciting today's weather","intent":"Weather.GetForecast","entities":[]},{"text":"forecast in celcius","intent":"Weather.GetForecast","entities":[]},{"text":"will it be raining in ranchi","intent":"Weather.GetForecast","entities":[]},{"text":"provide me by toronto weather please","intent":"Weather.GetForecast","entities":[]},{"text":"\"i need to know the temperature at bangor, me\"","intent":"Weather.GetForecast","entities":[]},{"text":"get the forcast for me","intent":"Weather.GetForecast","entities":[]},{"text":"find out tomorrow's weather","intent":"Weather.GetForecast","entities":[]},{"text":"book a flight from seattle to hong kong","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":30,"endPos":38},{"entity":"Location::LocationFrom","startPos":19,"endPos":25}]},{"text":"buy a plane ticket to bangor me","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":22,"endPos":30}]},{"text":"reservation for new york city","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":25,"endPos":28},{"entity":"Location","startPos":16,"endPos":23}]},{"text":"ticket to portland","intent":"BookFlight","entities":[{"entity":"Location::LocationTo","startPos":10,"endPos":17}]}],"settings":[{"name":"NormalizeDiacritics","value":"false"},{"name":"NormalizePunctuation","value":"false"}]}
	Response 201
	------------
        The ID of the imported application.

        "f8c64e2a-8635-4a09-8f78-39d7adc76ec5"

    Response 429
	------------
       Rate limit is exceeded.

    Response 400
	------------
    This error can be returned if the request's parameters are incorrect meaning the required parameters are missing, malformed, or too large.

	This error can be returned if the request's body is incorrect meaning the JSON is missing, malformed, or too large.

	This error is returned is your import JSON is incorrect. This is usual due to using values in the JSON that are no longer used or missing properties that are required. The error message will reference the exact property that is causing the problem.

    Response 401
	------------
        You do not have access.

        Reasons can include:

        used endpoint subscription key, instead of authoring key
        invalid, malformed, or empty authoring key
        authoring key doesn't match region
        you are not the owner or collaborator
        invalid order of API calls
        Response 403
        Total monthly key quota limit exceeded

    Referencia:
        https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5890b47c39e2bb052c5b9c31
]]--
function ImportApp (exportedApp, optionalName)
	local uri = MakeCompleteURI("APPS", "import")
	if optionalName then
		uri = uri .. "?" .. optionalName
	end
	optionalName = optionalName or exportedApp.name
	local success, response = request.Post(uri,exportedApp)
	if not success then
		LogError("[LUIS_APPS:ImportApp] Error importing APPLICATION %s. Error: '%s'", json.encode(exportedApp), json.encode(response))
		return false, response
	end
	local appId = response
	LogInfo("[LUIS_APPS:ImportApp] Success Importing APPLICATION on appId '%s'.", appId)
	return true, appId
end

--[[
-----------------------------
VERSIONS - DELETE UNLABELLED UTTERANCE
-----------------------------
	Deleted an unlabelled utterance.

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

	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
	------------
		text/plain
		"Dummy text"

	Response 200
	------------

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/58b6f32139e2bb139ce823c9
]]--
function DeleteAppSuggestedUtterance (appId, utteranceName, versionId)
	assert(appId)
	assert(utteranceName)
	assert(versionId)

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

	-- La palabra tiene que ir encerrada entre comillas porque asi lo espera el API
	utteranceName = "'" .. utteranceName .. "'"
	--[[
		Aunque en la documentacion indica que el request tiene que ser "text/plain", si se agrega ese contentType, falla y nos dice que tenemos
		que pasar el contentType "application/json" .......... PFFFFFFFFFFF
	]]--
	local success, response = request.Delete(uri, utteranceName, "application/json")
	if not success then
		LogError("[LUIS_APPS:DeleteAppSuggestedUtterance] Error deleting UTTERANCE NAME '%s' on appId '%s' versionId: '%s'. Response: '%s'", utteranceName, appId, versionId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:DeleteAppSuggestedUtterance] Success deleted UTTERANCE NAME '%s' on appId '%s' versionId: '%s'.", utteranceName, appId, versionId)

	return true, response
end

--[[
-----------------------------
APPS - Assign a LUIS azure accounts to an application
-----------------------------
Assigns an azure account to the application.

	Request URL
	------------
		https://[location].api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/azureaccounts

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

	Request headers
	------------
	Authorization string The bearer authorization header to use; containing the user's ARM token used to validate azure accounts information.
	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
	------------
		The azure account information object.
		application/json
		{
			"azureSubscriptionId": "{subscription_id}",
			"resourceGroup": "{resource_group_name}",
			"accountName": "{account_name}"
		}

	Response 429
	------------
		Rate limit is exceeded.

	Response 401
	------------
		You do not have access.

		Reasons can include:

		used endpoint subscription key, instead of authoring key
		invalid, malformed, or empty authoring key
		authoring key doesn't match region
		you are not the owner or collaborator
		invalid order of API calls

	Response 400
	------------
		The app ID is missing or invalid. The includeResponse is invalid.

		application/json
		The request is invalid.

	Response 403
	------------
		Total monthly key quota limit exceeded

	Response 201
	------------
		A message indicating success of operation.

		application/json
		{
			"code": "Success",
			"message": "Operation Successful"
		}

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be32228e8473de116325515

]]--
function AssignAzureAccountsResourceToApp (appId, vcc)
	assert(type(appId) == "string")
	assert(type(vcc) == "string")

	LogInfo("[LUIS_APPS:AssignAzureAccountsResourceToApp] Assigning Azure Account to app: '%s', vcc: '%s'.", appId, vcc)

	local success, vccAzureAccount, tokenInfo = azure.LoadAzureAccountAndToken(vcc)
	if not success then
		local err = vccAzureAccount
		LogError("[LUIS_APPS:AssignAzureAccountsResourceToApp] Error Retrieving Azure Account & Token. Error: '%s'", err)
		return false, err
	end

	-- "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ .... .... ... qaApUOSYbuMKsiD9Z7088dXwA"
	local additionalHeaders = {
		["Authorization"] = tokenInfo.token_type .. " " .. tokenInfo.access_token
	}

	local uri = MakeCompleteURI("APPS", "%s/azureaccounts", appId)

	local data = {
		azureSubscriptionId = vccAzureAccount.AzureSubscriptionId, -- "dc506e4a-ff4a-4178-9e18-1750b4247451"
		resourceGroup = vccAzureAccount.ResourceGroup, -- "inconcert_luis_grp",
		accountName = vccAzureAccount.AccountName -- "inconcert_luis"
	}

	local success, response = request.Post(uri, data, nil, additionalHeaders)
	if not success then
		LogError("[LUIS_APPS:AssignAzureAccountsResourceToApp] Error Assigning Azure Accounts to app '%s'. Error: '%s'", appId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_APPS:AssignAzureAccountsResourceToApp] Success Assigned Azure Accounts to app '%s'.", appId)

	return true, response
end

--[[
-----------------------------
APPS - Removes an assigned LUIS azure accounts from an application
-----------------------------
Gets the LUIS azure accounts for the user using his ARM token.

	Request URL
	------------
		https://[location].api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/azureaccounts

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

	Request headers
	------------
		Authorization string The bearer authorization header to use; containing the user's ARM token used to validate azure accounts information.
			Follow steps here to generate ARM Token: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be32228e8473de116325515
		Content-Type 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
	------------
		The azure account information object.
		application/json
		{
			"azureSubscriptionId": "{subscription_id}",
			"resourceGroup": "{resource_group_name}",
			"accountName": "{account_name}"
		}

	Response 429
	------------
		Rate limit is exceeded.

	Response 401
	------------
		You do not have access.

		Reasons can include:

		used endpoint subscription key, instead of authoring key
		invalid, malformed, or empty authoring key
		authoring key doesn't match region
		you are not the owner or collaborator
		invalid order of API calls

	Response 400
	------------
		The app ID is missing or invalid. The includeResponse is invalid.

		application/json
		The request is invalid.

	Response 403
	------------
		Total monthly key quota limit exceeded

	Response 200
	------------
		A message indicating success of operation.

		application/json
		{
			"code": "Success",
			"message": "Operation Successful"
		}

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be32554f8591db3a86232e1

]]--
function UnassignAzureAccountsResourceOfApp (appId, vcc)
	assert(type(appId) == "string")
	assert(type(vcc) == "string")

	LogInfo("[LUIS_APPS:UnassignAzureAccountsResourceOfApp] Unassigning Azure Account of app: '%s', vcc: '%s'.", appId, vcc)

	local success, vccAzureAccount, tokenInfo = azure.LoadAzureAccountAndToken(vcc)
	if not success then
		local err = vccAzureAccount
		LogError("[LUIS_APPS:UnassignAzureAccountsResourceOfApp] Error Retrieving Azure Account & Token. Error: '%s'", err)
		return false, err
	end

	-- "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ .... .... ... qaApUOSYbuMKsiD9Z7088dXwA"
	local additionalHeaders = {
		["Authorization"] = tokenInfo.token_type .. " " .. tokenInfo.access_token
	}

	local data = {
		azureSubscriptionId = vccAzureAccount.AzureSubscriptionId, -- "dc506e4a-ff4a-4178-9e18-1750b4247451"
		resourceGroup = vccAzureAccount.ResourceGroup, -- "inconcert_luis_grp",
		accountName = vccAzureAccount.AccountName -- "inconcert_luis"
	}

	local uri = MakeCompleteURI("APPS", "%s/azureaccounts", appId)

	local success, response = request.Delete(uri, data, nil, additionalHeaders)
	if not success then
		LogError("[LUIS_APPS:UnassignAzureAccountsResourceOfApp] Error Unassigning Azure Account Resource of App '%s'. Error: '%s'", appId, json.encode(response))
		return false, response
	end

	response = table.concat(response)
	LogInfo("[LUIS_APPS:UnassignAzureAccountsResourceOfApp] Success Unassigned Azure Account Resource of appId '%s'. Response", appId)
	--LogDebug("[LUIS_APPS:UnassignAzureAccountsResourceOfApp] Unassigned Azure Account Resource Response: '%s'", response)

	return true, response
end

--[[
-----------------------------
APPS - Get LUIS azure accounts assigned to the application
-----------------------------
Gets the LUIS azure accounts assigned to the application for the user using his ARM token.

	Request URL
	------------
		https://[location].api.cognitive.microsoft.com/luis/api/v2.0/apps/{appId}/azureaccounts

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

	Request headers
	------------
		Authorization string The bearer authorization header to use; containing the user's ARM token used to validate azure accounts information.
			Follow steps here to generate ARM Token: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be32228e8473de116325515
		Content-Type 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
	------------
		...

	Response 429
	------------
		Rate limit is exceeded.

	Response 401
	------------
		You do not have access.

		Reasons can include:

		used endpoint subscription key, instead of authoring key
		invalid, malformed, or empty authoring key
		authoring key doesn't match region
		you are not the owner or collaborator
		invalid order of API calls

	Response 400
	------------
		The app ID is missing or invalid. The includeResponse is invalid.

		application/json
		The request is invalid.

	Response 403
	------------
		Total monthly key quota limit exceeded

	Response 200
	------------
		A List of azure account information objects.

		application/json
		[
			{
				"AzureSubscriptionId": "{subscription_id}",
				"ResourceGroup": "{resource_group_name}",
				"AccountName": "{account_name}"
			}
		]

	Referencia: https://westus.dev.cognitive.microsoft.com/docs/services/5890b47c39e2bb17b84a55ff/operations/5be32554f8591db3a86232e1

]]--
function GetAssignedAzureAccountsResource (appId, tenantInfo)
	assert(type(appId) == "string")
	assert(type(tenantInfo) == "table")

	LogInfo("[LUIS_APPS:GetAssignedAzureAccountsResource] Retrieving Azure Account in app: '%s', tenantInfo: '%s'.", appId, json.encode(tenantInfo))

	local success, tokenInfo = azure.GetAzureResourceManagerToken(tenantInfo)
	--LogDebug("[LUIS_AZURE:GetAssignedAzureAccountsResource] Azure Resource Manager Token. success: '%s', token: '%s'", success, tokenInfo)

	if not success then
		local err = tokenInfo
		LogError("[LUIS_AZURE:GetAssignedAzureAccountsResource] Error Retrieving Azure Token. App: '%s'. Error: '%s'", appId, err)
		return false, err
	end

	-- "Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJ .... .... ... qaApUOSYbuMKsiD9Z7088dXwA"
	local additionalHeaders = {
		["Authorization"] = tokenInfo.token_type .. " " .. tokenInfo.access_token
	}

	local uri = MakeCompleteURI("APPS", "%s/azureaccounts", appId)

	local success, response = request.Get(uri, additionalHeaders)
	if not success then
		LogError("[LUIS_AZURE:GetAssignedAzureAccountsResource] Error Retrieving app: '%s' Azure Accounts Error: '%s'.", appId, json.encode(response))
		return false, response
	end

	LogInfo("[LUIS_AZURE:GetAssignedAzureAccountsResource] Success Retrieving Azure Accounts in app: '%s'.", appId)
	local encodedAzureAccountInApp = table.concat(response)
	LogDebug("[LUIS_AZURE:GetAssignedAzureAccountsResource] app: '%s', encodedAzureAccountInApp: '%s'", appId, encodedAzureAccountInApp)

	return true, encodedAzureAccountInApp
end
