import ch.nevis.esauth.auth.engine.AuthResponse
import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory
import ch.nevis.idm.client.HTTPRequestWrapper

import groovy.json.JsonSlurper
import groovy.xml.XmlSlurper

// Accounting
def requester = session['ch.nevis.auth.saml.request.scoping.requesterId'] ?: 'unknown'
def requestId = session['ch.nevis.auth.saml.request.id'] ?: 'unknown'
def requestedAq = session['agov.requestedRoleLevel'] ?: 'unknown'
def user = session['ch.adnovum.nevisidm.user.extId'] ?: 'unknown'
def credentialType = session['authenticatedWith'] ?: 'unknown'
def sourceIp = request.getLoginContext()['connection.HttpHeader.X-Real-IP'] ?: 'unknown'
def userAgent = request.getLoginContext()['connection.HttpHeader.user-agent'] ?: request.getLoginContext()['connection.HttpHeader.User-Agent'] ?: 'unknown'





IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)

String clientExtId = session.get('ch.adnovum.nevisidm.user.clientExtId')
String userExtId = session.get('ch.adnovum.nevisidm.user.extId')
String sessionId = session.get('ch.nevis.session.conversationId')

String endPoint = "${parameters.get('utility-service.baseUrl')}/api/v1/recovery/code"

def userDto = new XmlSlurper().parseText(session.get('ch.adnovum.nevisidm.userDto'))
def recoveryCredential = userDto.'**'.find {node -> node.name() == 'credentials' && node.type.text() == 'CONTEXT_PASSWORD' && node.context.text() == 'RECOVERY'}

// 1a) check if user has a credential
if ( recoveryCredential != null ) {
	LOG.debug("Account '${user}' has an active recovery code, no need to create new code")
	response.setResult('done')
	return
}

// 1b) check if a recovery is ongoing (nothing to do)
if (Arrays.stream(response.getActualRoles()).filter( r -> r.contains('AGOV-AccountStatus.recovery')).findAny().isPresent()) {
	LOG.debug("Account '${user}' is in recovery, no need to create new code")
	response.setResult('done')
	return
}


// 2) set cookie for recoveryCode
if (outargs.containsKey('out.JWTToken')) {
  def token = outargs.getProperty('out.JWTToken').bytes.encodeBase64().toString()
  def agovRecoveryCodeCookie = "agovRecoveryCode=${token }; Domain=${parameters.get('cookie.domain')}; Path=/; SameSite=Strict; Secure; HttpOnly"
  response.setHeader('Set-Cookie', agovRecoveryCodeCookie)
  outargs.remove('out.JWTToken')
}

// 3) generate code if not yet done
if (!session['agov.new.recovery.code.generated']) {
	inargs.remove('submit')
	try {
		def postRequest = new HTTPRequestWrapper()
		postRequest.addToHeaders('Content-Type',  ['application/json'])

		postRequest.setPayLoad("{\"userExtId\":\"$userExtId\",\"userSessionId\": \"$sessionId\"}".getBytes('UTF-8'))
		
        def result = idmRestClient.postWithResponse(endPoint, postRequest)
		if (result.getStatusCode() != 200) {
            LOG.debug("Payload: ${new String(postRequest.getPayLoad())}")
            LOG.debug("Result: ${result}")
			LOG.warn("Event='RCVRY-CODE', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='Failed to create code (http status code ${result.getStatusCode()})")
			response.setResult('failed')
			return
		}

		def json = new JsonSlurper().parseText(new String(result.getPayLoad(), 'UTF-8'))

		notes.setProperty('agov.new.recovery.code', json['recoveryCode']['code'].replaceAll('^(....)(....)(.*)$', '$1-$2-$3'))
		LOG.debug("agov.new.recovery.code: ${notes['agov.new.recovery.code']}")

		response.setSessionAttribute('agov.new.recovery.code.generated', 'true')
		def validTil = "${json['recoveryCode']['validUntil'][2]}.${json['recoveryCode']['validUntil'][1]}.${json['recoveryCode']['validUntil'][0]}"
		response.setSessionAttribute('agov.new.recovery.code.validTil', validTil)
		response.setSessionAttribute('agov.new.recovery.code.pdfAuthToken', json['authToken'])

		LOG.info("Event='RCVRY-CODE', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}'")

	} catch(Exception e) {
		LOG.warn("Event='RCVRY-CODE', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='Failed to create code (http status code ${e.getMessage()})")
		LOG.error("Recoverycode processing failed: $e")
		response.setResult('failed')
		return
	}

	response.setResult('encryptCode')
	return
}

if (inargs['submit']) {
	def agovRecoveryCodeCookie = "agovRecoveryCode=deleted; Domain=${parameters.get('cookie.domain')}; Path=/; Max-Age=0; SameSite=Strict; Secure; HttpOnly"
	response.setHeader('Set-Cookie', agovRecoveryCodeCookie)
	response.setResult('done')
	return
}

// show the GUI
response.setStatus(AuthResponse.AUTH_CONTINUE)
