import java.text.SimpleDateFormat
import groovy.text.SimpleTemplateEngine

import ch.nevis.idm.client.IdmRestClient
import ch.nevis.idm.client.IdmRestClientFactory

def getDateWithoutTimestamp(String date){
    def result = date
    if(date.matches('^[0-9-]+[+]{1}.*')){
        result = date.replaceAll('[+]{1}.*', "")
    }
    return result
}

// NOTE/aca/2025/06/19: We could also reload the data from idm after the update instead of updating the session variables manualy -> probably better and less error-prone
def compareAndUpdateSessionVariables(sess, keys, isProperty){
    def updatedKeys = []
    for(key in keys){
        def idmkey = isProperty ? "ch.nevis.idm.User.prop.$key" : "ch.nevis.idm.User.$key"
        def eidValue = session["agov.eid.User.$key"] ?: ""
        def idmValue = session[idmkey] ?: ""
        if(!idmValue || eidValue != idmValue){
            sess.setAttribute(idmkey, eidValue)
            updatedKeys.add(key)
        }
    }
    return updatedKeys
}

String user_update_dto_template = '''
{
    "name": {
        "firstName": "$firstName",
        "familyName": "$familyName"
    },
    "properties": {
        "svnr": "$svnr",
        "placeOfBirth": "$placeOfBirth",
        "nationality": "$nationality",
        "eIdNumber": "$eIdNumber"
    },
    "gender": "$gender",
    "birthDate": "$birthDate",

    "modificationComment": "updated user information with eid attributes during request $request"
}
'''

// 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'



def sess = request.getAuthSession(true)

// Convert EID gender format to IDM
if(sess.get('agov.eid.User.gender') == '1'){
    sess.setAttribute('agov.eid.User.gender', 'MALE')
}
if(sess.get('agov.eid.User.gender') == '2'){
    sess.setAttribute('agov.eid.User.gender', 'FEMALE')
}
if(sess.get('agov.eid.User.gender') == '3'){
    sess.setAttribute('agov.eid.User.gender', 'OTHER')
}

// Compare eid and idm attributes + update idm session variables if they differ 
def attributesToAudit = compareAndUpdateSessionVariables(sess, ["firstName", "lastName", "gender"], false)
// NOTE/aca/2025/06/14/: Potentally Throw a DATA ERROR if the properties are different? -> should the svnr number ever change?
def propertiesToAudit = compareAndUpdateSessionVariables(sess, ["svnr", "eIdNumber", "nationality", "placeOfBirth"], true)


// Handle birthdate seperately, since it can contain a timestamp -> we probably don't want to update if only the timestamp is wrong
String eidBirthdate = getDateWithoutTimestamp(session["agov.eid.User.birthDate"] ?: "")
String idmBirthdate = getDateWithoutTimestamp(session["ch.nevis.idm.User.birthDate"] ?: "")
LOG.debug("eidBirthdate: $eidBirthdate    idmBirthdate: $idmBirthdate")
if(eidBirthdate != idmBirthdate){
    sess.setAttribute("ch.nevis.idm.User.birthDate", eidBirthdate)
    // For some reson IdmGetPropertyState uses a different date format than IdmSetPropertyState?
    //def date = new SimpleDateFormat('yyyy-MM-dd').parse(eidBirthdate)
    //def idmFromatedBirthDate = new SimpleDateFormat('dd.MM.yyyy').format(date) 
    //sess.setAttribute("ch.nevis.idm.User.birthDate.idmFormat", idmFromatedBirthDate)
    attributesToAudit.add("birthDate") 
}

// Check if we need to update IDM
def auditedRequired = attributesToAudit.size() > 0 || propertiesToAudit.size() > 0

if(auditedRequired){
    // update attributes in idm & transition to User notification
    IdmRestClient idmRestClient = IdmRestClientFactory.get(parameters)

    String baseUrl = parameters.get("baseUrl")
    String clientExtId = parameters.get("clientExtId")
    String endPoint = "$baseUrl/api/core/v1"
    String userExtId = sess.getAttribute("ch.nevis.idm.User.extId")

    String requestUrl = "$endPoint/$clientExtId/users/$userExtId"


    
    def binding = [
        "firstName":        sess.getAttribute('agov.eid.User.firstName'), 
        "familyName":       sess.getAttribute('agov.eid.User.lastName'),
        "svnr":             sess.getAttribute('agov.eid.User.svnr'),
        "placeOfBirth":     sess.getAttribute('agov.eid.User.placeOfBirth'),
        "nationality":      sess.getAttribute('agov.eid.User.nationality'),
        "eIdNumber":        sess.getAttribute('agov.eid.User.eIdNumber'),
        "gender":           sess.getAttribute('agov.eid.User.gender').toLowerCase(),
        "birthDate":        sess.getAttribute('agov.eid.User.birthDate'),
        "request":          requestId
        ]

    def templateEngine = new SimpleTemplateEngine()
    def userUpdateDto = templateEngine.createTemplate(user_update_dto_template).make(binding).toString()

    try {
        idmRestClient.patch(requestUrl, userUpdateDto)
    
    }catch(Exception e) {
        LOG.error("Failed to update User data in IDM: ${e}")
        LOG.error("Event='DATAERROR', Requester='${requester}', RequestId='${requestId}', RequestedAq=${requestedAq}, User=${user}, CredentialType='${credentialType}', SourceIp=${sourceIp}, UserAgent='${userAgent}', reason='Failed to update User data in IDM'")
        response.setResult('error')
        return
    }
    String printKeys = attributesToAudit.toListString()
    LOG.debug("AuditedAttributes: $printKeys")
 
    // Transform gender back to number
    if(sess.get('ch.nevis.idm.User.gender') == 'MALE'){
        sess.setAttribute('ch.nevis.idm.User.gender', '1')
    }
    if(sess.get('ch.nevis.idm.User.gender') == 'FEMALE'){
        sess.setAttribute('ch.nevis.idm.User.gender', '2')
    }
    if(sess.get('ch.nevis.idm.User.gender') == 'OTHER'){
        sess.setAttribute('ch.nevis.idm.User.gender', '3')
    }

    response.setResult('audited')
}else{
    // Attributes match & no notification needed => continue by updating the linking credential and sending the saml assertion
    // NOTE/aca/2025/06/19: We skip checking the account state, recovery code, mobile number and LoA
     LOG.debug("No Audit Required: Logging user in")
    response.setResult('noChange')
}





