local request = require "luis.request"

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 "AZUREACCOUNTS"
	return m_instanceOwner:GetBaseURI(id)
end

-- *******************************************************************************
-- API AZURE ACCOUNTS
-- *******************************************************************************

function LoadVCCTenant (vcc)
	local api = require "luis"
	return api.LoadVCCTenantAzureAccount(vcc)
end

function LoadVCCAccounts (vcc)
	local api = require "luis"
	return api.LoadVCCAzureAccounts(vcc)
end

function LoadDefaultTenantAzureAccount ()
	return {
		tenant_id = "359e9065-2b08-4aae-9504-38e2a3b4b356",
		client_id = "d336fabc-9804-4186-8f8f-b40c52f39c6e",
		client_secret = "J]Z/1@x/4PJXG9K1+SIj96GaIQ:iLS1s",
		resource = "https://management.azure.com/"
	}
end

--[[
METHOD: Post

URI:
	https://login.microsoftonline.com/359e9065-2b08-4aae-9504-38e2a3b4b356/oauth2/token

HEADERS:
	Content-Type = "application/x-www-form-urlencoded"
	Cache-Control = "no-cache"

BODY:
	grant_type=client_credentials&client_id=d336fabc-9804-4186-8f8f-b40c52f39c6e&client_secret=J%5DZ%2F1%40x%2F4PJXG9K1%2BSIj96GaIQ%3AiLS1s&resource=https%3A%2F%2Fmanagement.azure.com%2F

		grant_type    = client_credentials
		client_id     = d336fabc-9804-4186-8f8f-b40c52f39c6
		client_secret = J]Z/1@x/4PJXG9K1+SIj96GaIQ:iLS1s      -- Tiene que ir encodeado (algo así = J%5DZ%2F1%40x%2F4PJXG9K1%2BSIj96GaIQ%3AiLS1s)
		resource      = https://management.azure.com/         -- Tiene que ir encodeado (algo así = https%3A%2F%2Fmanagement.azure.com%2F)

RESPONSE:
	200 ok
		[
		  "{\"token_type\":\"Bearer\",\"expires_in\":\"3600\",\"ext_expires_in\":\"3600\",\"expires_on\":\"1562680055\",\"not_before\":\"1562676155\",\"resource\":\"https://management.azure.com/\",\"access_token\":\"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiIsIng1dCI6IkN0ZlFDOExlLThOc0M3b0MyelFrWnBjcmZPYyIsImtpZCI6IkN0ZlFDOExlLThOc0M3b0MyelFrWnBjcmZPYyJ9.eyJhdWQiOiJodHRwczovL21hbmFnZW1lbnQuYXp1cmUuY29tLyIsImlzcyI6Imh0dHBzOi8vc3RzLndpbmRvd3MubmV0LzM1OWU5MDY1LTJiMDgtNGFhZS05NTA0LTM4ZTJhM2I0YjM1Ni8iLCJpYXQiOjE1NjI2NzYxNTUsIm5iZiI6MTU2MjY3NjE1NSwiZXhwIjoxNTYyNjgwMDU1LCJhaW8iOiI0MlpnWUZpb3UvYmI3NzBmVnNvdllMNFp0V3YzWndBPSIsImFwcGlkIjoiZDMzNmZhYmMtOTgwNC00MTg2LThmOGYtYjQwYzUyZjM5YzZlIiwiYXBwaWRhY3IiOiIxIiwiaWRwIjoiaHR0cHM6Ly9zdHMud2luZG93cy5uZXQvMzU5ZTkwNjUtMmIwOC00YWFlLTk1MDQtMzhlMmEzYjRiMzU2LyIsIm9pZCI6IjJmYjJlYTdmLWFmYzItNGIzZS1iM2NjLTRiN2JjODY1ODQ1MyIsInN1YiI6IjJmYjJlYTdmLWFmYzItNGIzZS1iM2NjLTRiN2JjODY1ODQ1MyIsInRpZCI6IjM1OWU5MDY1LTJiMDgtNGFhZS05NTA0LTM4ZTJhM2I0YjM1NiIsInV0aSI6IkhRQ29UeFR1TVVpa2YzWjNGZHk5QUEiLCJ2ZXIiOiIxLjAifQ.GP0pZ4RXeOmJoW3xNBEnaR8mhuqoWVfExZ6a956-aCMi3LT9jsc_IdmNlFR_KSkR1FFjtA1VOqM4Ghhlt-7UosG-NrxVk63r-UmGuIeFdIPguBAmR8pcN8tNl3gcxm2uTeqSXyRh0uuUbXiZDMoa7gpwSFhIBPtvsa8DE2mCQAdf6ztX2g9f8TGki7zzu75kbOPCPr7PYTWt3LAljXUfV8ayKOezDxANHtUaGGgoOrcdkr_5Njecq7F6LjxESMOMzjEZtd_i_Y64Ft9JRAGXypJ-QcTXiY4noo-IrFzjeP3nDv7ah7g6NGYRqdfA8x3kFfzTP4hRgKV1jvN7FWhT6Q\"}"
		]

	Donde podemos obtener tipo de Token en el atributo "token_type" y el token en el atributo "access_token"


]]--
function GetAzureResourceManagerToken (tenantInfo)
	assert(type(tenantInfo) == "table")
	assert(type(tenantInfo.tenant_id) == "string")
	assert(type(tenantInfo.client_id) == "string")
	assert(type(tenantInfo.client_secret) == "string")
	assert(type(tenantInfo.resource) == "string")

	local uri = "https://login.microsoftonline.com/%s/oauth2/token"
	uri = string.format(uri, tenantInfo.tenant_id)

	local additionalHeaders = {
		["Cache-Control"] = "no-cache"
	}

	local body = "grant_type=client_credentials&" ..
		"client_id=%s&" ..
		"client_secret=%s&" ..
		"resource=%s"

	body = string.format(body, tenantInfo.client_id, request.UrlEncode(tenantInfo.client_secret), request.UrlEncode(tenantInfo.resource))

	local contentType = "application/x-www-form-urlencoded"

	local success, response = request.Post(uri, body, contentType, additionalHeaders)
	if not success then
		local err = response
		LogError("[LUIS_AZURE:GetAzureResourceManagerToken] Get an Azure Resource Manager token. Error: '%s'", json.encode(err))
		return false, err
	end

	LogInfo("[LUIS_AZURE:GetAzureResourceManagerToken] Success Get an Azure Resource Manager token:\n%s.", json.encode(response))
	local encodedTokenInfo = response[1]
	--LogDebug("[LUIS_AZURE:GetAzureResourceManagerToken] encodedTokenInfo: '%s'", encodedTokenInfo)

	return true, json.decode(encodedTokenInfo)
end

--[[

]]--
function LoadAzureAccountAndToken (vcc)
	assert(type(vcc) == "string")

	local vccAzureAccounts, total = LoadVCCAccounts(vcc)
	if total == 0 then
		local err = {reason = "VCC has not assigned Azure Accounts", vcc = vcc}
		LogError("[LUIS_AZURE:LoadAzureAccountAndToken] VCC %s has not assigned Azure Accounts.", vcc)
		return false, err
	end
	local vccAzureSubscriptionId = next(vccAzureAccounts)
	local vccAzureAccount = vccAzureAccounts[vccAzureSubscriptionId]

	--LogDebug("1 LoadAzureAccountAndToken vccAzureAccount %s -> %s", vcc, json.encode(vccAzureAccount))

	local vccTenants, total = LoadVCCTenant(vcc)
	if total == 0 then
		local err = {reason = "VCC has not assigned Tenant Azure Accounts", vcc = vcc}
		LogError("[LUIS_AZURE:LoadAzureAccountAndToken] VCC %s has not assigned Tenant Azure Accounts.", vcc)
		return false, err
	end
	local vccTenantId = next(vccTenants)
	local tenantInfo = vccTenants[vccTenantId]
	LogDebug("2 LoadAzureAccountAndToken tenantInfo %s -> %s", vcc, json.encode(tenantInfo))

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

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

	--LogDebug("[LUIS_AZURE:LoadAzureAccountAndToken] Success Loaded Azure Account & Token. Azure '%s', Token: '%s'.", json.encode(vccAzureAccounts), json.encode(tokenInfo))

	return true, vccAzureAccount, tokenInfo, vccTenants
end

--[[
-----------------------------
USER - Get LUIS azure accounts
-----------------------------
Gets the LUIS azure accounts for the user using his ARM token.

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


	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

		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/5be313cec181ae720aa2b26c
]]--

function LoadAzureAccounts (tenantInfo)
	assert(type(tenantInfo) == "table")
	assert(type(tenantInfo.tenant_id) == "string")
	assert(type(tenantInfo.client_id) == "string")
	assert(type(tenantInfo.client_secret) == "string")
	assert(type(tenantInfo.resource) == "string")

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

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

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

	local uri = GetBaseURI()

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

	LogInfo("[LUIS_AZURE:LoadAzureAccounts] Success Loaded Azure Accounts.")
	local encodedAzureAccounts = table.concat(response)
	--LogDebug("[LUIS_AZURE:LoadAzureAccounts] encodedAzureAccounts: '%s'", encodedAzureAccounts)

	return true, encodedAzureAccounts
end
