def runExternalPublishTask(String gradleTask) {
    def maxAttempts = 3

    for (def attempt = 1; attempt <= maxAttempts; attempt++) {
        try {
            sh "./gradlew ${gradleTask}"
            return
        } catch (org.jenkinsci.plugins.workflow.steps.FlowInterruptedException e) {
            throw e
        } catch (Exception e) {
            if (attempt >= maxAttempts) {
                throw e
            }

            echo "External publish task '${gradleTask}' failed on attempt ${attempt}/${maxAttempts}; retrying in 2 minutes."
            sleep time: 2, unit: 'MINUTES'
        }
    }
}

pipeline {
    agent any
    tools {
        jdk "jdk-25"
    }

    environment {
      ORG_GRADLE_PROJECT_curseforgeApikey = credentials("jei-curseforge-key")
      ORG_GRADLE_PROJECT_modrinthToken = credentials("modrinth-auth-token")
      ORG_GRADLE_PROJECT_BUILD_NUMBER = "${env.BUILD_NUMBER}"
      DISCORD_WEBHOOK_URL = credentials("jei-discord-webhook-url")
      GITHUB_RELEASE_COMMENT_TOKEN = credentials("github-release-comment-token")
      GITHUB_RELEASE_COMMENT_EXPECTED_LOGIN = "mezz-bot"
    }
    stages {
        stage('Clean') {
            steps {
                echo 'Cleaning Project'
                sh 'chmod +x gradlew'
                sh './gradlew clean'
            }
        }

        stage('Build') {
            steps {
                sh "./gradlew :Fabric:build"
                sh "./gradlew :NeoForge:build"
                sh "./gradlew :Common:build"
                sh "./gradlew :CommonApi:build"
                sh "./gradlew :Gui:build"
                sh "./gradlew :Library:build"
                sh "./gradlew :Debug:build"
                sh "./gradlew :FabricApi:build"
                sh "./gradlew :NeoForgeApi:build"
            }
        }

        stage('API Compatibility') {
            steps {
                sh "./gradlew checkApiCompatibility"
            }
        }

        stage('Server GameTests') {
            steps {
                sh "./gradlew :NeoForge:runGameTestServer"
            }
        }

        stage('Client GameTests') {
            steps {
                sh '''
                    if command -v xvfb-run >/dev/null 2>&1; then
                        xvfb-run --auto-servernum --server-args="-screen 0 1280x720x24" ./gradlew :Fabric:runClientGameTest :Fabric:runClientGameTestWithoutAmecs :NeoForge:runClientRecipeSyncTest --no-daemon --no-parallel
                    else
                        echo "ERROR: xvfb-run is not available; skipping client GameTests." >&2
                    fi
                '''
            }
        }

        stage('Check Publish Changes') {
            steps {
                script {
                    def publishGuard = load '.jenkins/publishGuard.groovy'
                    env.SHOULD_PUBLISH = publishGuard.shouldPublishArtifacts() ? 'true' : 'false'
                }
            }
        }

        stage('Publish Maven') {
            when {
                expression { env.SHOULD_PUBLISH != 'false' }
            }
            steps {
                sh "./gradlew :Gui:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :Library:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :Fabric:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :NeoForge:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :Common:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :CommonApi:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :FabricApi:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
                sh "./gradlew :NeoForgeApi:publish -PDEPLOY_DIR=${env.MAVEN_DEPLOY_DIR}"
            }
        }

        stage('Publish CurseForge') {
            when {
                expression { env.SHOULD_PUBLISH != 'false' }
            }
            steps {
                script {
                    catchError(buildResult: 'FAILURE', stageResult: 'FAILURE', catchInterruptions: false) {
                        runExternalPublishTask(':Fabric:publishCurseforge')
                    }
                    catchError(buildResult: 'FAILURE', stageResult: 'FAILURE', catchInterruptions: false) {
                        runExternalPublishTask(':NeoForge:publishCurseforge')
                    }
                }
            }
        }

        stage('Publish Modrinth') {
            when {
                expression { env.SHOULD_PUBLISH != 'false' }
            }
            steps {
                script {
                    catchError(buildResult: 'FAILURE', stageResult: 'FAILURE', catchInterruptions: false) {
                        runExternalPublishTask(':Fabric:publishModrinth')
                    }
                    catchError(buildResult: 'FAILURE', stageResult: 'FAILURE', catchInterruptions: false) {
                        runExternalPublishTask(':NeoForge:publishModrinth')
                    }
                }
            }
        }

        stage('Comment GitHub Release') {
            when {
                expression { env.SHOULD_PUBLISH != 'false' && env.GITHUB_RELEASE_COMMENT_TOKEN }
            }
            steps {
                catchError(buildResult: 'SUCCESS', stageResult: 'UNSTABLE') {
                    withEnv(["GITHUB_TOKEN=${env.GITHUB_RELEASE_COMMENT_TOKEN}"]) {
                        sh "python3 .jenkins/githubReleaseComments.py"
                    }
                }
            }
        }

    }
    post {
        always {
            junit allowEmptyResults: true, testResults: '*/build/test-results/**/*.xml'
            script {
                def discordNotification = load '.jenkins/discordNotification.groovy'
                discordNotification.notifyDiscordBuildSafely(currentBuild.currentResult)
            }
        }
    }
}
