pipeline {
    agent {
        kubernetes {
            yaml '''
apiVersion: v1
kind: Pod
spec:
  initContainers:
  - name: install-uv
    image: icr.io/taas-jenkins-public/jonk/agent-jnlp:latest
    command: ['sh', '-c']
    args:
      - |
        set -eux
        curl -LsSf https://astral.sh/uv/install.sh | env UV_INSTALL_DIR=/opt/uv/bin sh
    volumeMounts:
    - name: uv-bin
      mountPath: /opt/uv/bin
  containers:
  - name: jnlp
    env:
    - name: JENKINS_JAVA_OPTS
      value: -Xmx512m -XX:+UnlockExperimentalVMOptions -XX:+UseContainerSupport -Dorg.jenkinsci.plugins.gitclient.Git.timeOut=60
    - name: PATH
      value: /opt/uv/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
    image: icr.io/taas-jenkins-public/jonk/agent-jnlp:latest
    imagePullPolicy: Always
    resources:
      requests:
        memory: "1Gi"
        cpu: "250m"
      limits:
        memory: "4Gi"
        cpu: "2"
    volumeMounts:
    - name: dev-shm
      mountPath: /dev/shm
    - name: uv-bin
      mountPath: /opt/uv/bin
  volumes:
  - name: dev-shm
    emptyDir:
      medium: Memory
      sizeLimit: 256Mi
  - name: uv-bin
    emptyDir: {}
'''
        }
    }

    parameters {
        string(
            name: 'BRANCH',
            defaultValue: 'master',
            description: 'The branch of the SDK repository to build from.'
        )
        string(
            name: 'PYPI_VERSION',
            defaultValue: '',
            description: 'A version identifier used for publishing to PyPI. Example: 5.2.0b1'
        )
        choice(
            name: 'PYPI_INSTANCE',
            choices: ['test', 'production'],
            description: '''Which PyPI instance to publish to.
            <p><b>WARNING: Publishing permanently uses that version number. Be very careful when publishing to production.</b></p>'''
        )
        string(
            name: 'BRANCH_TAG',
            defaultValue: '',
            description: '''<p>This is a postfix to the git tag.</p>
            <p>Default is: "v$PYPI_VERSION", i.e. "v5.2.0b1"</p>
            <p>When BRANCH_TAG is given: PyPI release "v$PYPI_VERSION+$BRANCH_TAG"</p>'''
        )
    }

    environment {
        SDK_VERSION_FILE='python/streamsets/sdk/__version__.py'
        VENV_DIR = "${env.WORKSPACE}/venv"
    }

    stages {
        stage('Check Parameters') {
            steps {
                script {
                    if (!env.PYPI_VERSION?.trim()) {
                        error "No version provided via the PYPI_VERSION environment variable."
                    }

                    withCredentials([
                        string(credentialsId: 'pypi-test-token', variable: 'PYPI_TOKEN_TEST'),
                        string(credentialsId: 'pypi-prod-token', variable: 'PYPI_TOKEN_PROD')
                    ]) {
                        if (env.PYPI_INSTANCE == 'production') {
                            env.TWINE_USERNAME = '__token__'
                            env.TWINE_PASSWORD = PYPI_TOKEN_PROD  // pragma: allowlist secret
                        } else if (env.PYPI_INSTANCE == 'test') {
                            env.TWINE_REPOSITORY_URL = 'https://test.pypi.org/legacy/'
                            env.TWINE_USERNAME = '__token__'
                            env.TWINE_PASSWORD = PYPI_TOKEN_TEST  // pragma: allowlist secret
                        } else {
                            error "Invalid or empty value for PYPI_INSTANCE. Valid options are: {production, test}."
                        }
                    }
                }
            }
        }

        stage('Checkout SDK from GitHub') {
            steps {
                dir('sdk') {
                    git(
                        url: 'https://github.ibm.com/ibmstreamsets/sdk.git',
                        credentialsId: 'github-streamsetsci',
                        branch: "${params.BRANCH}"
                    )
                }
            }
        }

        stage('Ensure git doesnt scream') {
            steps {
                sh 'git config --global --add safe.directory ${WORKSPACE}'
            }
        }

        stage('Install Requirements') {
            steps {
                sh '''
                    uv venv "$VENV_DIR" --python 3.10
                    . "$VENV_DIR/bin/activate"

                    cd python
                    git config --unset-all core.hooksPath || true
                    # Install build requirements (from make setup)
                    uv pip install -r build_requirements.txt
                    uv pip install -r test_requirements.txt
                    # Install additional tools needed for publishing
                    uv pip install --upgrade pip wheel twine pre-commit
                    cd ../
                '''
            }
        }

        stage('Update Version') {
            steps {
                sh '''
                    . "$VENV_DIR/bin/activate"
                    echo "Updating version number to: ${PYPI_VERSION}"
                    sed -i.old "s/\\".*\\"/\\"${PYPI_VERSION}\\"/" ${SDK_VERSION_FILE}
                    rm ${SDK_VERSION_FILE}.old
                '''
            }
        }

        stage('Build') {
            steps {
                sh '''
                    . "$VENV_DIR/bin/activate"
                    cd python
                    echo 'Building'
                    uv build
                '''
            }
        }

        stage('Sign and Verify Artifacts') {
            steps {
                withCredentials([
                    string(credentialsId: 'code_signing_password', variable: 'CODE_SIGNING_P12_PASSWORD'),
                    string(credentialsId: 'code_signing_pfx', variable: 'pfx_file'),
                ]) {
                    script {
                        def codeSigningPfxFile = '/tmp/code_signing.pfx'

                        sh "echo '${pfx_file}' | base64 -d > ${codeSigningPfxFile}"

                        // https://github.ibm.com/TAAS/Jenkins-on-Kubernetes/blob/main/doc/reference/jenkins-agent-image.md#about-garasign
                        def garasignOutput = withEnv([
                            "CODE_SIGNING_PFX_FILE=${codeSigningPfxFile}",
                        ]) {
                            sh(script: '''
                                set -e
                                # Setup garasign client and capture output
                                echo "=== Setting up Garasign client ==="
                                setup-garasign-client
                                echo "=== Extracting key alias ==="
                                KEY_ALIAS=$(/opt/Garantir/bin/garasign listkeys | awk '/Found key:/ {print $NF; exit}')
                                echo "Found key alias: ${KEY_ALIAS}"
                                echo "=== Exporting public key ==="
                                /opt/Garantir/bin/garasign export --key "${KEY_ALIAS}" --outputDirectory /tmp/public-keys
                                echo "=== Getting COSIGN_KEY URI ==="
                                COSIGN_KEY=$(cosign pkcs11-tool list-keys-uris --module-path /usr/local/lib/Garantir/GRS/libgrsp11.so --slot-id 1 | awk '/URI:/ {print $NF; exit}')
                                # Output values for Jenkins to capture
                                echo "KEY_ALIAS=${KEY_ALIAS}"
                                echo "COSIGN_CERT_CHAIN=/tmp/public-keys/${KEY_ALIAS}.pem.chain"
                                echo "COSIGN_KEY=${COSIGN_KEY}"
                            ''', returnStdout: true)
                        }

                        // Parse the output and set environment variables
                        garasignOutput.split('\n').each { line ->
                            if (line.startsWith('KEY_ALIAS=')) {
                                env.KEY_ALIAS = line.substring('KEY_ALIAS='.length())
                            } else if (line.startsWith('COSIGN_CERT_CHAIN=')) {
                                env.COSIGN_CERT_CHAIN = line.substring('COSIGN_CERT_CHAIN='.length())
                            } else if (line.startsWith('COSIGN_KEY=')) {
                                env.COSIGN_KEY = line.substring('COSIGN_KEY='.length())
                            }
                        }

                        echo "✓ Garasign setup complete. Key: ${env.KEY_ALIAS}"
                    }

                    dir('python') {
                        withEnv([
                            "COSIGN_KEY=${env.COSIGN_KEY}",
                            "CODE_SIGNING_P12_PASSWORD=${env.CODE_SIGNING_P12_PASSWORD}"
                        ]) {
                            sh '''
                                echo "=== Creating attestations directory ==="
                                mkdir -p attestations
                                echo "=== Signing distribution files with cosign ==="
                                for file in dist/*.whl dist/*.tar.gz; do
                                    if [ -f "$file" ]; then
                                        filename=$(basename "$file")
                                        echo "Signing: $filename"
                                        cosign sign-blob --yes \
                                            --key "${COSIGN_KEY}" \
                                            --tlog-upload=false \
                                            --output-signature "attestations/${filename}.sig" \
                                            --output-certificate "attestations/${filename}.crt" \
                                            "$file"
                                        # Verify files were created
                                        echo "Checking generated signature and certificate:"
                                        ls -l "attestations/${filename}.sig" "attestations/${filename}.crt"
                                        echo "✓ Signed: $filename"
                                    fi
                                done
                                echo "=== Code signing complete ==="
                                ls -lh dist/
                                echo "=== Attestations created ==="
                                ls -lh attestations/
                                echo "=== Verifying signed artifacts ==="
                                failed=0
                                for file in dist/*.whl dist/*.tar.gz; do
                                    if [ -f "$file" ]; then
                                        filename=$(basename "$file")
                                        echo "Verifying file: $file"
                                        echo "Using signature: attestations/${filename}.sig"
                                        if ! cosign verify-blob \
                                            --key "${COSIGN_KEY}" \
                                            --signature "attestations/${filename}.sig" \
                                            --insecure-ignore-tlog \
                                            "$file"; then
                                            echo "✗ Verification failed for $filename"
                                            failed=1
                                        else
                                            echo "✓ Verification successful for $filename"
                                        fi
                                    fi
                                done
                                if [ $failed -eq 1 ]; then
                                    echo "=== Verification failed for one or more artifacts ==="
                                    exit 1
                                fi
                                echo "=== All artifacts verified successfully ==="
                            '''
                        }
                    }
                }
            }
        }

        stage('Archive Artifacts') {
            steps {
                dir('python') {
                    archiveArtifacts artifacts: 'dist/*.whl, dist/*.tar.gz, attestations/*.sig, attestations/*.crt', fingerprint: true
                }
            }
        }

        stage('Upload') {
            steps {
                sh '''
                    echo ""
                    echo "Releasing version ${PYPI_VERSION} to the ${PYPI_INSTANCE} PyPI."
                    echo ""
                    . "$VENV_DIR/bin/activate"
                    cd python
                    set +e
                    uv run twine upload --non-interactive dist/*.whl dist/*.tar.gz
                    RESULT=$?
                    set -e
                    if [ $RESULT -ne 0 ]; then
                        echo "Twine failed to execute. Cleaning up and bailing." >&2
                        rm -rf dist/ build/ streamsets_testframework.egg-info/
                        exit 1
                    fi
                '''
            }
        }

        stage('Cleanup') {
            steps {
                sh '''
                    rm -rf dist/ build/ streamsets_testframework.egg-info/ "$VENV_DIR"
                '''
            }
        }
    }
}
