def call(Map args) {
    assert (args.awsRegions && args.imageTag && args.imageName): 'awsRegions, imageTag and imageName arguments must be passed.'
    assert (args.functionName || args.environment): 'One of functionName or environment must be passed.'
    assert (!args.awsDeploymentTargetAccountId || args.awsDeploymentRoleName): 'If awsDeploymentTargetAccountId is passed then awsDeploymentRoleName must also be passed.'
    assert (!args.awsDeploymentRoleName || args.awsDeploymentTargetAccountId): 'If awsDeploymentRoleName is passed then awsDeploymentTargetAccountId must also be passed.'
    assert args.awsRegions.getClass() in Collection: 'awsRegions must be a list or set of regions'

    // These variables need default values
    String functionName = args.functionName ?: "${args.environment}-${args.imageName}"
    boolean publishVersion = args.publishVersion == null ? false: args.publishVersion

    /*
     * The checkout directory must be unique per parallel branch. functionName alone can collide
     * when the same function name is deployed to multiple accounts in parallel (e.g. environments
     * sharing an envTag), which causes a git index.lock race during checkout. The target account
     * ID disambiguates the branches, so append it when present.
    */
    String workspaceDir = "lambdaDeploy/${functionName}" + (args.awsDeploymentTargetAccountId ? "-${args.awsDeploymentTargetAccountId}" : '')

    List<String> environmentVariables = []

    /*
     * If arguments include optional parameters, set environment variable to that value.
     * If not, no need to set it as the deployment script has working defaults.
    */
    def optionalParameters = ['ecrRegistryAccountId', 'ecrRegistryRegion']
    for (def parameter in optionalParameters) {
        if (args."${parameter}") {
            def envVar = parameter.replaceAll('([A-Z])', '_$1').toUpperCase()
            println "Optional parameter provided - setting environment variable ${envVar}"
            environmentVariables << "${envVar}=${args."${parameter}"}"
        }
    }

    dir(workspaceDir) {
        checkout([$class: 'GitSCM', branches: [[name: '*/master']], doGenerateSubmoduleConfigurations: false, extensions: [], submoduleCfg: [], userRemoteConfigs: [[credentialsId: '577cbc72-7d9e-4eba-924c-ecbbe6de9805', url: "git@github.com:theorchard/python-deployment-utils.git"]]])
        for (def region in args.awsRegions) {
            withEnv([
                "AWS_REGION=${region}",
                *environmentVariables
            ]) {
                println "Deploying to ${region}"
                if (args.awsDeploymentRoleName && args.awsDeploymentTargetAccountId) {
                    withAWS(role: args.awsDeploymentRoleName, roleAccount: args.awsDeploymentTargetAccountId, roleSessionName: args.awsDeploymentRoleName, useNode: true) {
                        println "IAM role name provided - using ${args.awsDeploymentRoleName} as deployment role"
                        deploy(functionName, args.imageTag, args.imageName, publishVersion, args.aliasName)
                    }
                } else {
                    deploy(functionName, args.imageTag, args.imageName, publishVersion, args.aliasName)
                }
            }
        }
    }
}

def deploy(String functionName, String imageTag, String imageName, boolean publishVersion, String aliasName) {
    List<String> args = [
        "-f ${functionName}",
        "-t ${imageTag}",
        "-i ${imageName}"
    ] as List<String>

    if (publishVersion) {
        args += '-p'
    }
    if (aliasName) {
        args += "-a ${aliasName}"
    }

    dir('lambda') {
        sh label: "Lambda Deploy", script: """
        set +x

        echo "AWS_REGION is \${AWS_REGION}"
        echo "ECR_REGISTRY_ACCOUNT_ID is \${ECR_REGISTRY_ACCOUNT_ID}"

        python3 -m venv venv
        . ./venv/bin/activate

        pip install -r requirements.txt

        set -x

        python -u update_containerized_lambda.py ${args.join(' ')}
        """
    }
}
