pipeline {
    agent any

    options {
        ansiColor('xterm')
        disableConcurrentBuilds()
        timeout(time: 60, unit: 'MINUTES')
        timestamps()
    }

    parameters {
        choice(
            name: 'ENVIRONMENT',
            choices: ['staging', 'production'],
            description: 'Target environment for deployment'
        )
        string(
            name: 'SHARED_LIBRARIES_VERSION',
            defaultValue: 'master',
            description: 'Version of Jenkins shared libraries to use'
        )
    }

    triggers {
        issueCommentTrigger('.*retest this please.*')
        parameterizedCron(
            '''
            H 4,11 * * 1-5 % ENVIRONMENT=production
            '''
        )
    }

    environment {
        // Build information
        BUILD_ID = "${env.BUILD_NUMBER}"
        BUILDER_IMAGE_NAME = "project-builder:${env.BUILD_NUMBER}"
        
        // GitHub configuration
        GITHUB_REPOSITORY = 'rs-tools'
        
        // Timeouts (minutes)
        BUILD_TIMEOUT_MIN = 30
        DEPLOY_TIMEOUT_MIN = 15
        DB_MIGRATIONS_TIMEOUT_MIN = 15
        
        // Notifications
        SLACK_NOTIFICATIONS_CHANNEL = '#rs-jenkins'
    }

    stages {
        stage('Initialize') {
            steps {
                script {
                    // Set environment-specific variables
                    if (params.ENVIRONMENT == 'production') {
                        env.ARCHIVE_NAME = "build_rstools_production_${BUILD_ID}.tar"
                        env.ARCHIVE_DIR = "build_rstools_production_${BUILD_ID}"
                        env.REMOTE_HOST = "172.31.0.10" // rpsweb01
                        env.SSH_CREDENTIALS = "royaltyshare_prod_ssh"
                        env.BRANCH_DISPLAY = "production"
                        env.DB_CREATE_SCRIPT = "/app/tools/dbadmin/bin/create_sites_production.sh"
                        env.DTMV_CREATE_SCRIPT = "/app/tools/dbadmin/bin/create_dtmv_sites_production.sh"
                        env.DB_DEPLOY_FLAGS = "--start --sync --dryrun --prodmode"
                        env.DB_DEPLOY_FINAL_FLAGS = "--start --prodmode"
                        env.DB_CREATE_CONTINUE_ON_ERROR = "|| :"
                        env.LN_COMMAND="ln -sfn"
                    } else {
                        env.ARCHIVE_NAME = "build_rstools_master_${BUILD_ID}.tar"
                        env.ARCHIVE_DIR = "build_rstools_master_${BUILD_ID}"
                        env.REMOTE_HOST = "172.31.80.14" // awstaging
                        env.SSH_CREDENTIALS = "royaltyshare_awstaging"
                        env.BRANCH_DISPLAY = "master"
                        env.DB_CREATE_SCRIPT = "/app/tools/dbadmin/bin/create_sites_staging.sh"
                        env.DTMV_CREATE_SCRIPT = "/app/tools/dbadmin/bin/create_dtmv_sites_staging.sh"
                        env.DB_DEPLOY_FLAGS = "--start --sync --dryrun"
                        env.DB_DEPLOY_FINAL_FLAGS = "--start"
                        env.DB_CREATE_CONTINUE_ON_ERROR = ""
                        env.LN_COMMAND="sudo ln -sfn"
                    }
                }
            }
        }

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

        stage('Compliance Checks') {
            steps {
                complianceChecks()
            }
        }

        stage('Validate Software Catalog') {
            steps {
                datadogSoftwareCatalogValidate()
            }
        }

        stage('Static Application Security Tests') {
            steps {
                sastTests()
            }
        }

        stage('SonarQube Analysis') {
            when {
                branch 'master'
            }
            steps {
                sonarScan project: GITHUB_REPOSITORY, language: 'perl', exclusions: '**/sysadmin/wordpress/**,**/common/production**,**/pp-frontend/**', qualityGateTimeout: 600
            }
        }

        stage('Build and Archive') {
            when {
                branch 'master'
            }
            steps {
                script {
                    timeout(time: env.BUILD_TIMEOUT_MIN, unit: 'MINUTES') {
                        buildAndArchiveApplication()
                    }
                }
            }
        }

        stage('Deploy and Test') {
            when {
                branch 'master'
            }
            steps {
                script {
                    timeout(time: env.DEPLOY_TIMEOUT_MIN, unit: 'MINUTES') {
                        deployToRemoteHost(env.SSH_CREDENTIALS)
                    }
                }
            }
        }

        stage('Restart Apache on Additional Hosts (Production)') {
            when {
                allOf {
                    branch 'master'
                    expression { params.ENVIRONMENT == 'production' }
                }
            }
            steps {
                script {
                    sshagent(credentials: [env.SSH_CREDENTIALS]) {
                        def remoteUser = "jenkins"
                        def additionalHosts = [
                            '172.31.0.10', //rpsweb01'
                            '172.31.16.10', //rpsweb02'
                            '172.31.32.10', //rpsweb03'
                            '172.31.32.12', //bpweb02'
                        ]

                        echo "==> Restarting Apache on additional production hosts..."
                        for (host in additionalHosts) {
                            echo "---> Restarting Apache on ${host}..."
                            try {
                                restartApache(remoteUser, host)
                            } catch (Exception e) {
                                echo "WARNING: Failed to restart Apache on ${host}: ${e.message}"
                            }
                        }
                        echo "Apache restart completed on additional hosts"
                    }
                }
            }
        }

        stage('Publish Software Catalog') {
            when {
                allOf {
                    branch 'master'
                    expression { params.ENVIRONMENT == 'production' }
                }
            }
            steps {
                datadogSoftwareCatalogPublish()
            }
        }
    }

    post {
        success {
            script {
                if (env.GIT_BRANCH == 'master') {
                    slackNotify channel: env.SLACK_NOTIFICATIONS_CHANNEL, stepName: "environment: ${params.ENVIRONMENT}"
                }
            }
        }
        failure {
            script {
                if (env.GIT_BRANCH == 'master') {
                    slackNotify channel: env.SLACK_NOTIFICATIONS_CHANNEL, stepName: "environment: ${params.ENVIRONMENT}"
                }
            }
        }
        regression {
            script {
                if (env.GIT_BRANCH == 'master') {
                    slackNotify channel: env.SLACK_NOTIFICATIONS_CHANNEL, stepName: "environment: ${params.ENVIRONMENT}"
                }
            }
        }
        fixed {
            script {
                if (env.GIT_BRANCH == 'master') {
                    slackNotify channel: env.SLACK_NOTIFICATIONS_CHANNEL, stepName: "environment: ${params.ENVIRONMENT}"
                }
            }
        }
        always {
            echo "--> Cleaning up Docker image..."
            script {
                if (env.GIT_BRANCH == 'master') {
                    sh "docker rmi ${BUILDER_IMAGE_NAME}"
                }
            }
            echo "Pipeline completed for ${params.ENVIRONMENT} environment"
        }
        cleanup {
            cleanWs()
        }
    }
}

// ===========================
// Reusable Functions
// ===========================

def buildAndArchiveApplication() {
    echo "--> 1. Building the builder image..."
    withCredentials([string(credentialsId: 'github_packages_token', variable: 'GIT_TOKEN')]) {
        sh """
            docker build \
                -f sysadmin/conf/docker/Dockerfile.frontend \
                -t ${BUILDER_IMAGE_NAME} \
                --build-arg GIT_TOKEN="\${GIT_TOKEN}" \
                .
        """
    }
    
    echo "--> 2. Extracting built code and creating archive..."
    def containerId = sh(
        script: "docker run -d ${BUILDER_IMAGE_NAME} tail -f /dev/null",
        returnStdout: true
    ).trim()
    
    try {
        sh "mkdir -p builds"
        sh "docker cp ${containerId}:/app/common/ ."
        sh "docker cp ${containerId}:/app/pp-frontend/build ./pp-frontend"
        
        // Create archive with exclusions
        def excludePatterns = [
            './node_modules',
            './pp-frontend/node_modules',
            './src',
            './.git',
            './pp-frontend/src',
            './gulpfile.js',
            './gulp-config',
            './pp-frontend/package.json',
            './pp-frontend/.*',
            './pp-frontend/webpack.config.*',
            './pp-frontend/yarn.lock',
            './.eslintrc.js',
            './.stylelintrc',
            './.editorconfig',
            './.gitignore'
        ].collect { "--exclude=${it}" }.join(' ')
        
        sh "tar -cf builds/${env.ARCHIVE_NAME} ${excludePatterns} ."
        
        echo "--> Archive created: builds/${env.ARCHIVE_NAME}"
    } finally {
        echo "--> Cleaning up temporary container..."
        sh "docker stop ${containerId} || true"
        sh "docker rm ${containerId} || true"
    }
}

def deployToRemoteHost(String sshCredentialsId) {
    sshagent(credentials: [sshCredentialsId]) {
        def remoteUser = "jenkins"
        def remoteHost = env.REMOTE_HOST
        def remoteSrcPath = "/app/shared/jenkins_builds_new"
        
        echo "==> Uploading application artifact..."
        sh "test -f builds/${env.ARCHIVE_NAME} || { echo 'Archive file not found!'; exit 1; }"
        sh """
            ssh -o StrictHostKeyChecking=no ${remoteUser}@${remoteHost} \
                'mkdir -p ${remoteSrcPath}'
            scp -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null \
                builds/${env.ARCHIVE_NAME} \
                ${remoteUser}@${remoteHost}:${remoteSrcPath}/
        """
        
        echo "==> Deploying application code..."
        deployApplicationCode(remoteUser, remoteHost, remoteSrcPath)
        
        echo "==> Running remote tests..."
        runRemoteTests(remoteUser, remoteHost)
        
        echo "==> Switching to new deployment..."
        activateDeployment(remoteUser, remoteHost, remoteSrcPath)
        
        echo "==> Running database migrations..."
        runDatabaseMigrations(remoteUser, remoteHost)
        
        echo "==> Restarting Apache..."
        restartApache(remoteUser, remoteHost)
        
        echo ">>>>> Deployment successful! <<<<<"
    }
}

def deployApplicationCode(String remoteUser, String remoteHost, String remoteSrcPath) {
    sh """
        ssh ${remoteUser}@${remoteHost} '
            set -e
            echo "---> [STEP 1: PREPARE] Deploying application code..."
            mkdir -p ${remoteSrcPath}/${env.ARCHIVE_DIR}
            tar -xf ${remoteSrcPath}/${env.ARCHIVE_NAME} -C ${remoteSrcPath}/${env.ARCHIVE_DIR}
            echo "---> [INFO] Deployment files extracted"
            echo "---> [INFO] Playwright images should already be available"
        '
    """
}

def runRemoteTests(String remoteUser, String remoteHost) {
    sh """
        ssh ${remoteUser}@${remoteHost} '
            set -e
            echo "---> [STEP 2: RUN TESTS] Running Playwright smoketests..."
            docker run --rm docker-pw-tests || {
                echo "ERROR: Playwright tests failed!"
                exit 1
            }
            
            echo "---> [STEP 2.1: RUN TESTS] Running Perl unit tests..."
            perl /app/shared/jenkins_builds/tests/rps/lib/RPS/DB/Item/Artist.t || {
                echo "ERROR: Perl tests failed!"
                exit 1
            }
            
            echo "---> [SUCCESS] All tests passed!"
        '
    """
}

def activateDeployment(String remoteUser, String remoteHost, String remoteSrcPath) {
    sh """
        ssh ${remoteUser}@${remoteHost} '
            set -e
            echo "---> [STEP 3: GO LIVE] Switching symlink..."
            ${env.LN_COMMAND} ${remoteSrcPath}/${env.ARCHIVE_DIR} /app/shared/builds/current
            echo "---> Symlink updated to point to new deployment"
        '
    """
}

def runDatabaseMigrations(String remoteUser, String remoteHost) {
    sh """
        ssh ${remoteUser}@${remoteHost} '
            set -e
            echo "---> [STEP 4: DB MIGRATIONS] Running DB Deploy (timeout: ${env.DB_MIGRATIONS_TIMEOUT_MIN} min)..."
            
            timeout ${env.DB_MIGRATIONS_TIMEOUT_MIN}m bash -c "
                echo Running DB migrations...
                
                echo Creating sites database...
                /bin/bash ${env.DB_CREATE_SCRIPT} ${env.DB_CREATE_CONTINUE_ON_ERROR}
                sleep 5
                
                echo Creating DTMV sites database...
                /bin/bash ${env.DTMV_CREATE_SCRIPT} ${env.DB_CREATE_CONTINUE_ON_ERROR}
                sleep 5
                
                echo Running db_deploy in dry-run mode...
                /app/tools/common/bin/db_deploy.pl ${env.DB_DEPLOY_FLAGS}
                
                echo Running db_deploy for real...
                /app/tools/common/bin/db_deploy.pl ${env.DB_DEPLOY_FINAL_FLAGS}
                
                sleep 3
                echo DB migrations completed successfully
            " || {
                echo "ERROR: DB migrations failed or timed out!"
                exit 1
            }
        '
    """
}

def restartApache(String remoteUser, String remoteHost) {
    sh """
        ssh ${remoteUser}@${remoteHost} '
            echo "---> [STEP 5: RESTART APACHE] Restarting Apache web server..."
            sudo /usr/sbin/apachectl restart
            echo "---> Apache restarted successfully"
        '
    """
}
