# signature { license=0, seed=277031123, key="0eaee6ad960677f82713652f0b015c9f" }
-- ----------------------------------------------------------------------------



local api =
{
}

package.loaded.api = api

local format = string.format
local socket = import( 'socket' )



math.randomseed( os.time() )
local uuids = 0
local uuidf = format
(
	'%08x-%04x-%04x-%04x-%%06x%06x',
	os.time(),
	math.random( 0xffff ),
	math.random( 0xffff ),
	math.random( 0xffff ),
	math.random( 0x100000, 0xffffff )
)

local function uuid()
	uuids = uuids + 1
	return format( uuidf, uuids )
end




local requestf =
'%s /%s HTTP/1.1\r\n\z
 %sHost: %s\r\n\z
 Content-Type: application/json\r\n\z
 Content-Length: %d\r\n\r\n%s'

local function http( method, url, headers, body )
	local tls, host, port, resource = url:match('^(https?)://([^:/]+):?(%d*)/?(.*)')
	tls = tls == 'https'
	if port == '' then port = tls and 443 or 80 end
	body = body or ''

	local sock = socket.tcp()
	sock:settimeout( 10 )

	local res, reason = sock:connect( host, tonumber( port ) )
	if not res then
		return nil, "Could not establish TCP connection to LMS server, error:"..reason
	end

	_G.OwnIP = sock:getsockname()

	local ok, err
	if tls then
		sock, err = require( 'ssl' ).wrap( sock, { protocol='tlsv1_2', mode='client', verify='none' } )
		if not sock then return nil, err end


		sock:settimeout( 10 )

		ok, err = sock:dohandshake()
		if not ok then return nil, err end
	end

	local request = requestf:format( method, resource, headers or '', host, #body, body )
	sock:send( request )
	dump( request )


	local status = sock:receive()


	local D = { status }


	local length, chunked
	repeat
		local line = sock:receive()
		if not line then break end
		table.insert( D, line )
		line = line:lower()
		length = length or tonumber( line:match( 'content%-length%s*:%s*(%d+)' ) )
		chunked = chunked or line:match( 'transfer%-encoding%s*%:%s*(chunked)' )
	until line == ''


	local response = ''

	if length then
		response = sock:receive( length ) or ''
	end

	while chunked do

		length = sock:receive()
		table.insert( D, length )
		length = tonumber( length, 16 )


		if ( length or 0 ) == 0 then break end


		local chunk = sock:receive( length ) or ''
		table.insert( D, chunk..'\r' )
		response = response .. ( chunk )


		sock:receive( 2 )
	end

	sock:close()
	table.insert( D, response )
	dump( table.concat( D, '\n' ) )

	return response, status, err
end




function api.authenticate()
	local json = '{"clientId":"%s","clientSecret":"%s","Grant_type":"client_credentials"}'
	local body = format( json, cfg.ClientId, cfg:password( 'Client' ) )
	local response = http( 'POST', cfg.AuthServerURL, '', body )

	json = api.decode( response )
	local token = json.success and json.data and json.data.token

	if token then api.token = token end

	return response
end




function api.request( method, resource, fmt, ... )

	if not api.token then
		local response = api.authenticate()
		if not api.token then
			return response
		end
	end

	local body = format( fmt or '', ... )
	local headers = format( 'X-requestId: %s\r\nAuthorization: Bearer %s\r\n', uuid(), api.token or '' )

	return http( method, cfg.LMServerURL .. resource, headers, body )
end


api.post = function( ... ) return api.request( 'POST', ... ) end
api.get  = function( ... ) return api.request( 'GET',  ... ) end



api.decode = function( json )
	json = json or '{}'


	json = json:gsub( '%[', '{' ):gsub( '%]', '}' )


	json  = json:gsub( '"([^"]+)"[ \t]*:', '%1=' )


	local code, error = load( 'return '..json, '','t', {} )

	if code then return code() end

	dump( error )

	return {}
end

return api
