def AWS_REGIONS = ['us-east-1']
def ECR_ACCOUNT_ID = '086679231553'
def QA_ACCOUNT_ID = '619719722105'
def PROD_ACCOUNT_ID = '926734670777'
def QA_DEPLOYMENT_ROLE = 'qa-songwhip-jenkins-pipeline-deploy-role'
def PROD_DEPLOYMENT_ROLE = 'prod-songwhip-jenkins-pipeline-deploy-role'
def SLACK_NOTIFICATIONS_CHANNEL = '#songwhip-alerts-dev'

@groovy.transform.Field
List<String> functionsToBuild = null

// Map of lambda folder names to actual lambda function names (if different)
def lambdaNames = [
    'api-sqs-processor': 'songwhip-api-sqs-processor'
]

def vulnerabilitiesToIgnore = [
    'CVE-2025-64756', // Glob vulnerability
    'CVE-2026-23745', // node-tar vulnerability
    'CVE-2026-23950', // node-tar vulnerability
    'CVE-2025-15467',
    'CVE-2025-13151'
]

pipeline {
    agent {
        label 'aws'
    }

    parameters {
        booleanParam(name: 'DEPLOY_LAMBDAS_TO_PROD', defaultValue: true, description: 'Whether or not to deploy lambdas to production')
        string(name: 'LAMBDA_FUNCTION_NAME', defaultValue: '', description: 'Names of specific lambda separated by commas to build/deploy (leave empty to auto-detect changes)')
        string(name: 'SHARED_LIBRARIES_VERSION', defaultValue: 'master', description: 'The version of the Jenkins shared libraries to use. Can be a branch, tag or Git revision.')
    }

   triggers {
        issueCommentTrigger('.*retest this please.*')
    }

    stages {
        stage('Load Shared Libraries') {
            steps {
                library "jenkins-global-libraries@${params.SHARED_LIBRARIES_VERSION}"
            }
        }

        stage('Tests') {
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Testing ${functionName}"
                        nodeSh(
                            user: 'root',
                            script: """
                                # install pnpm and dependencies
                                corepack enable
                                pnpm install --frozen-lockfile

                                # run tests
                                pnpm --filter ${functionName} test:lint
                                pnpm --filter ${functionName} test:types
                                pnpm --filter ${functionName} test:unit
                            """
                        )
                    }
                }
            }
        }

        stage('Validate Software Catalog Definition') {
            steps {   
                script {         
                    getFunctionsToBuild().each { functionName ->
                        echo "Validating Software Catalog for ${functionName}"
                        datadogSoftwareCatalogValidate(servicePath: "lambda/${functionName}")
                    }
                }
            }
        }

        stage('Static Application Security Tests'){
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Checking ${functionName}"
                        dir("lambda/${functionName}") {
                            sastTests()
                        }
                    }
                }
            }
        }

        stage('Build and Push to ECR'){
            when {
                branch 'master'
            }
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Building ${functionName}"
                        withCredentials([string(credentialsId: 'github_packages_token', variable: 'GITHUB_NPM_TOKEN')]) {
                            dockerToEcr (
                                awsRegions: AWS_REGIONS,
                                ecrAccountId: ECR_ACCOUNT_ID,
                                imageName: "lambda-songwhip-${functionName}",
                                imageTag: env.GIT_COMMIT,
                                dockerBuildSecrets: [
                                    [id: "GITHUB_NPM_TOKEN", env: "GITHUB_NPM_TOKEN"]
                                ],
                                dockerBuildArgs: [
                                    "LAMBDA_NAME": functionName,
                                    "DD_VERSION": env.GIT_COMMIT.take(7)
                                ]
                            )
                        }
                    }
                }
            }
        }

        stage('Scan Images'){
            when {
                branch 'master'
            }
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Scanning ${functionName}"
                        dir("lambda/${functionName}") {
                            dockerScan (
                                awsRegion: AWS_REGIONS[0],
                                ecrAccountId: ECR_ACCOUNT_ID,
                                imageName: "lambda-songwhip-${functionName}",
                                imageTag: env.GIT_COMMIT,
                                vulnerabilitiesToIgnore: vulnerabilitiesToIgnore
                            )
                        }
                    }
                }
            }
        }

        stage('Deploy to QA') {
            when {
                branch 'master'
            }
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Deploying ${functionName} to QA"
                        dir("lambda/${functionName}") {
                            lambdaDeploy (
                                environment: 'qa',
                                awsRegions: AWS_REGIONS,
                                imageTag: env.GIT_COMMIT,
                                imageName: "lambda-songwhip-${functionName}",
                                functionName: "qa-${lambdaNames[functionName] ?: "lambda-songwhip-${functionName}"}",
                                ecrRegistryAccountId: ECR_ACCOUNT_ID,
                                awsDeploymentTargetAccountId: QA_ACCOUNT_ID,
                                awsDeploymentRoleName: QA_DEPLOYMENT_ROLE
                            )
                        }
                    }
                }
            }
        }

        stage('Publish Software Catalog Definition') {
            when {
                branch 'master'
            }
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Publishing Software Catalog Definition for ${functionName}"
                        datadogSoftwareCatalogPublish(servicePath: "lambda/${functionName}")
                    }
                }
            }
        }

        stage('Deploy to PROD') {
            when {
                allOf {
                    branch 'master'
                    expression { params.DEPLOY_LAMBDAS_TO_PROD }
                }
            }
            steps {
                script {
                    getFunctionsToBuild().each { functionName ->
                        echo "Deploying ${functionName} to PROD"
                        dir("lambda/${functionName}") {
                            lambdaDeploy (
                                environment: 'prod',
                                awsRegions: AWS_REGIONS,
                                imageTag: env.GIT_COMMIT,
                                imageName: "lambda-songwhip-${functionName}",
                                functionName: "prod-${lambdaNames[functionName] ?: "lambda-songwhip-${functionName}"}",
                                ecrRegistryAccountId: ECR_ACCOUNT_ID,
                                awsDeploymentTargetAccountId: PROD_ACCOUNT_ID,
                                awsDeploymentRoleName: PROD_DEPLOYMENT_ROLE
                            )
                        }
                    }
                }
            }
        }
    }

    post {
        regression {
            script {
                if (env.BRANCH_NAME == 'master') {
                    slackNotify channel: SLACK_NOTIFICATIONS_CHANNEL
                }
            }
        }
        fixed {
            script {
                if (env.BRANCH_NAME == 'master') {
                    slackNotify channel: SLACK_NOTIFICATIONS_CHANNEL
                }
            }
        }
        failure {
            cleanWs()
            echo "Pipeline failed for commit: ${env.GIT_COMMIT}. Workspace cleaned."
        }
    }
}

def getFunctionsToBuild() {
    if (this.@functionsToBuild != null) {
        return this.@functionsToBuild
    }

    def lambdaFunctionName = params.LAMBDA_FUNCTION_NAME ?: null

    if (lambdaFunctionName) {
        // Deploy specific lambda(s) requested by parameter (supports comma-separated)
        this.@functionsToBuild = lambdaFunctionName.split(',').collect { it.trim() }
    } else {
        // Auto-detect changed lambdas on master branch
        def lambdaPackageFiles = findFiles(glob: 'lambda/**/package.json')
        
        // Extract directory paths from package.json paths (e.g. "lambda/foo/package.json" -> "lambda/foo/")
        def lambdaDirectories = lambdaPackageFiles.collect { it.path.replaceAll('package.json$', '') }

        def modifiedDirectories = getModifiedPaths(
            branchName: env.BRANCH_NAME,
            baseCommit: env.GIT_PREVIOUS_SUCCESSFUL_COMMIT,
            paths: lambdaDirectories
        )

        // Extract function name from directory path (last segment)
        this.@functionsToBuild = modifiedDirectories.collect { it.tokenize('/').last() }
    }

    if (this.@functionsToBuild) {
        currentBuild.description = "Lambdas: " + this.@functionsToBuild.join(', ')
    }

    return this.@functionsToBuild
}
