String GITHUB_REPOSITORY = 'scripts-sound-recording'
String ECR_ACCOUNT_ID = '086679231553'
List<String> AWS_REGIONS = ['us-east-1']
String SLACK_NOTIFICATIONS_CHANNEL = '#content-sr-fingerprint'
String QA_ACCOUNT_ID = '437795906767'
String QA_DEPLOYMENT_ROLE = 'prod-jenkins-aws-pipeline-agent'
String PROD_ACCOUNT_ID = '437795906767'
String PROD_DEPLOYMENT_ROLE = 'prod-jenkins-aws-pipeline-agent'

TASK_CONFIG = [
    'ddex-generator': [
        test: true,
        build: true,
        deployType: null,
        language: 'python',
        softwareCatalog: false,
        vulnerabilitiesToIgnore: [],
    ],
]

pipeline {
    agent none

    options {
        ansiColor('xterm')
        disableConcurrentBuilds()
        timestamps()
    }

    parameters {
        booleanParam(
            name: 'DEPLOY_TO_PROD',
            defaultValue: false,
            description: 'Whether or not to deploy to prod.'
        )
        string(
            name: 'TASK_NAMES',
            defaultValue: '',
            description: 'Comma-separated list of directories to build. If not specified, all modified directories will be built.'
        )
        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('Compliance Checks') {
            agent any
            steps {
                complianceChecks()
            }
        }
        stage('Validate Software Catalog Definitions') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    script {
                        if (config.softwareCatalog == true) {
                            datadogSoftwareCatalogValidate(servicePath: project)
                        } else {
                            echo "No software catalog definition configured for project: ${project}"
                        }
                    }

                }
            }
        }
        stage('Static Application Security Tests') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    sastTests(projectDir: project)
                }
            }
        }

        stage('Unit Tests and Style Checks') {
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    withEnv(["COMPOSE_PROJECT_NAME=${env.BUILD_TAG.toLowerCase()}-${project.replaceAll('/', '-')}"]) {
                        withEcr {
                            script {
                                if (config.test == true) {
                                    dir(project) {
                                        try {
                                            sh "docker compose run --rm --build lint-and-test"
                                        }
                                        finally {
                                            sh 'docker compose down --remove-orphans'
                                        }
                                    }
                                } else {
                                    echo "No unit tests or style checks configured for project: ${project}"
                                }
                            }
                        }
                    }
                }
            }
        }

        stage('Sonar Scan and Analysis') {
            when {
                branch 'master'
            }
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    sonarScan project: "${GITHUB_REPOSITORY}-${project.replaceAll('_', '-')}",
                        language: config.language,
                        projectBaseDir: project
                }
            }
        }
        stage('Create a Release') {
            when {
                anyOf {
                    branch 'master'
                    expression { env.GITHUB_COMMENT =~ 'build docker' }
                }
            }
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    script {
                        if (config.build == true) {
                            withCredentials([string(credentialsId: 'composer-github-auth', variable: 'COMPOSER_AUTH'),]) {
                                dockerToEcr awsRegions: AWS_REGIONS,
                                    ecrAccountId: ECR_ACCOUNT_ID,
                                    imageName: project.replaceAll('_', '-'),
                                    imageTag: env.GIT_COMMIT,
                                    dockerBuildContext: project,
                                    dockerBuildFile: "${project}/Dockerfile",
                                    dockerBuildSecrets: [[id: 'COMPOSER_AUTH', env: 'COMPOSER_AUTH']], // TODO: only set this when needed
                                    dockerBuildTarget: 'app'
                            }
                        } else {
                            echo "No build configured for project: ${project}"
                        }
                    }
                }
            }
        }
        stage('Deploy to QA') {
            when {
                branch 'master'
            }
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    script {
                        if (config.deployType != null) {
                            fargateDeploy awsRegions: AWS_REGIONS,
                                gitCommit: env.GIT_COMMIT,
                                serviceName: project.replaceAll('_', '-'),
                                ecrRegistryAccountId: ECR_ACCOUNT_ID,
                                environment: 'qa',
                                deployType: config.deployType,
                                awsDeploymentTargetAccountId: QA_ACCOUNT_ID,
                                awsDeploymentRoleName: QA_DEPLOYMENT_ROLE
                        } else {
                            echo "No deployment configured for project: ${project}"
                        }
                    }
                }
            }
        }
        stage('Scan Docker Image') {
            when {
                anyOf {
                    branch 'master'
                    expression { env.GITHUB_COMMENT =~ 'build docker' }
                }
            }
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    script {
                        if (config.build == true) {
                            dockerScan awsRegion: AWS_REGIONS[0],
                                ecrAccountId: ECR_ACCOUNT_ID,
                                imageName: project.replaceAll('_', '-'),
                                imageTag: env.GIT_COMMIT,
                                vulnerabilitiesToIgnore: config.vulnerabilitiesToIgnore
                        } else {
                            echo "No build configured for project: ${project}"
                        }
                    }
                }
            }
        }
        stage('Deploy to Prod') {
            when {
                allOf {
                    branch 'master'
                    expression { params.DEPLOY_TO_PROD }
                }
            }
            steps {
                withModifiedProjects(checkout: true) { project, config ->
                    script {
                        if (config.deployType != null) {
                            fargateDeploy awsRegions: AWS_REGIONS,
                                gitCommit: env.GIT_COMMIT,
                                serviceName: project.replaceAll('_', '-'),
                                ecrRegistryAccountId: ECR_ACCOUNT_ID,
                                environment: 'prod',
                                deployType: config.deployType,
                                awsDeploymentTargetAccountId: PROD_ACCOUNT_ID,
                                awsDeploymentRoleName: PROD_DEPLOYMENT_ROLE
                        } else {
                            echo "No build configured for project: ${project}"
                        }
                        if (config.softwareCatalog == true) {
                            datadogSoftwareCatalogPublish(servicePath: project)
                        }
                    }
                }
            }
        }
    }

    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
                }
            }
        }
    }
}

def withModifiedProjects(Map args = [:], Closure steps) {
    getMonorepoUtils().withModifiedProjects(args, steps)
}

def getMonorepoUtils() {
    return library("jenkins-global-libraries@${params.SHARED_LIBRARIES_VERSION}").com.sonymusic.MonorepoUtils.getInstance(
        steps: this,
        projectConfig: TASK_CONFIG,
        projectsToBuild: params.TASK_NAMES ? params.TASK_NAMES.split(',') : null
    )
}
