def setCommitStatus(String pStatus, String errorHint = '') {
    switch (pStatus) {
        case 'running':
            pState = 'running'
            pMessage = ""
            break
        case 'success':
            pState = 'success'
            pMessage = ":white_check_mark: ${env.JOB_NAME} :penguin: <b>MEGAchat</b> SUCCEEDED :muscle:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'aborted':
            pState = 'canceled'
            pMessage = ":interrobang: ${env.JOB_NAME} :penguin: <b>MEGAchat</b> ABORTED :confused:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'build_failure':
            pState = 'failed'
            pMessage = ":red_circle: ${env.JOB_NAME} :penguin: <b>MEGAchat</b> FAILURE :worried:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'tests_failure':
            pState = 'failed'
            pMessage = "🟠 ${env.JOB_NAME} :penguin: <b>MEGAchat</b> FAILURE :worried:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        case 'unstable':
            pState = 'failed'
            pMessage = ":interrobang: ${env.JOB_NAME} :penguin: <b>MEGAchat</b> UNSTABLE :confused:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
            break
        default:
            pState = 'failed'
            pMessage = ":interrobang: ${env.JOB_NAME} :penguin: <b>MEGAchat</b> UNKNOWN :confused:<br/>Build results: [Jenkins [${env.BUILD_DISPLAY_NAME}]](${env.RUN_DISPLAY_URL})<br/>Commit: ${env.GIT_COMMIT}"
    }
    if (pMessage) {
        if (errorHint) {
            pMessage += '<br/> ' + errorHint
        }
        addGitLabMRComment(comment: pMessage)
    }
    updateGitlabCommitStatus(name: "${PIPELINE_NAME}", state: pState)
}

def CUSTOM_TIMEOUT

pipeline {
    agent none
    options {
        buildDiscarder(logRotator(numToKeepStr: '135', daysToKeepStr: '21'))
        gitLabConnection('GitLabConnectionJenkins')
    }

    environment {
        PIPELINE_NAME = 'Build & test MEGAchat'
        BUILD_OPTIONS = ' '
        APIURL_TO_TEST = ' '
    }

    stages {
        stage('Update Gitlab commitStatus') {
            agent any
            steps {
                updateGitlabCommitStatus(name: 'Build & test MEGAchat', state: 'running')
                script{
                    COMMIT_ID = env.GIT_COMMIT
                    println GIT_COMMIT
                }
            }
        }
        stage('Build') {
            agent { label 'linux && amd64' }
            stages {
                stage('clean previous runs'){
                    steps{
                        deleteDir()
                    }
                }
                stage('Get build parameters'){
                    parallel{
                        stage('Get build options'){
                            steps {
                                script{
                                    BUILD_OPTIONS = sh(script: 'echo "$gitlabTriggerPhrase" | grep BUILD_OPTIONS | awk -F "BUILD_OPTIONS="  \'{print \$2}\' | cut -d"\\"" -f2 || :', returnStdout: true).trim()
                                    TESTS_PARALLEL = sh(script: 'echo "$gitlabTriggerPhrase" | grep "\\-\\-sequence" >/dev/null 2>&1 && echo "" || echo "--INSTANCES:10"', returnStdout: true).trim()
                                    GTEST_REPEAT = sh(script: 'echo "$gitlabTriggerPhrase" | grep --only-matching "\\-\\-gtest_repeat=[^ ]*" | awk -F "gtest_repeat="  \'{print "--gtest_repeat="\$2}\'|| :', returnStdout: true).trim()
                                    GTEST_FILTER = sh(script: 'echo "$gitlabTriggerPhrase" | grep --only-matching "\\-\\-gtest_filter=[^ ]*" | awk -F "gtest_filter="  \'{print "--gtest_filter="\$2}\'|| :', returnStdout: true).trim()
                                    CUSTOM_TIMEOUT = sh(script: 'echo "$gitlabTriggerPhrase" | grep --only-matching "\\-\\-timeout=[^ ]*" | awk -F "timeout="  \'{print \$2}\'|| :', returnStdout: true).trim()
                                    CUSTOM_TIMEOUT = CUSTOM_TIMEOUT? CUSTOM_TIMEOUT : "150"
                                    println BUILD_OPTIONS
                                    println TESTS_PARALLEL
                                    println GTEST_REPEAT
                                    println GTEST_FILTER
                                    println CUSTOM_TIMEOUT
                                }
                            }
                        }

                        stage('Get MEGAchat branch'){
                            steps {
                                script{
                                    env.MEGACHAT_BRANCH = sh(script: 'echo "$gitlabMergeRequestDescription" | grep MEGACHAT_BRANCH_TO_TEST | awk -F "MEGACHAT_BRANCH_TO_TEST="  \'{print \$2}\' | cut -d" " -f1', returnStdout: true).trim()
                                    if (MEGACHAT_BRANCH == ""){
                                        echo "MEGACHAT_BRANCH was not found on description so develop will be used by default"
                                        env.MEGACHAT_BRANCH = "develop"
                                    }
                                    println MEGACHAT_BRANCH
                                }
                            }
                        }

                        stage('Get API URL'){
                            steps {
                                script{
                                    APIURL_TO_TEST = sh(script: 'echo "$gitlabMergeRequestDescription" | grep USE_APIURL_TO_TEST | awk -F "USE_APIURL_TO_TEST="  \'{print \$2}\' | cut -d" " -f1', returnStdout: true).trim()
                                    println APIURL_TO_TEST
                                    if (APIURL_TO_TEST == ""){
                                        APIURL_TO_TEST = "https://g.api.mega.co.nz/"
                                        echo "APIURL_TO_TEST was not found on description so ${APIURL_TO_TEST} will be used by default"
                                    }
                                    echo "APIURL_TO_TEST will be ${APIURL_TO_TEST}"
                                }
                            }
                        }
                    }
                }


                stage('Checkout SDK and MEGAchat'){
                    steps {
                        //Clone MEGAchat
                        sh "echo Cloning MEGAchat branch \"${MEGACHAT_BRANCH}\""
                        checkout([
                            $class: 'GitSCM',
                            branches: [[name: "origin/${MEGACHAT_BRANCH}"]],
                            userRemoteConfigs: [[ url: "${env.GIT_URL_MEGACHAT}", credentialsId: "12492eb8-0278-4402-98f0-4412abfb65c1" ]],
                            extensions: [
                                [$class: "UserIdentity",name: "jenkins", email: "jenkins@jenkins"]
                                ]
                        ])
                        dir('third-party/mega'){
                            //Clone SDK (with PreBuildMerge)
                            checkout([
                                $class: 'GitSCM',
                                branches: [[name: "origin/${env.gitlabSourceBranch}"]],
                                userRemoteConfigs: [[ url: "${env.GIT_URL_SDK}", credentialsId: "12492eb8-0278-4402-98f0-4412abfb65c1" ]],
                                extensions: [
                                    [$class: "UserIdentity",name: "jenkins", email: "jenkins@jenkins"],
                                    [$class: 'PreBuildMerge', options: [fastForwardMode: 'FF', mergeRemote: "origin", mergeStrategy: 'DEFAULT', mergeTarget: "${env.gitlabTargetBranch}"]]
                                    ]
                            ])
                        }
                        script{
                            megachat_sources_workspace = WORKSPACE
                            sdk_sources_workspace = "${megachat_sources_workspace}/third-party/mega"
                        }
                    }
                    post {
                        failure {
                            script {
                                setCommitStatus('build_failure', ':red_circle: Checkout failed')
                            }
                            echo 'Error: Checkout stage failed'
                        }
                    }
                }

                stage('Build MEGAchat'){
                    environment{
                        VCPKGPATH = "/opt/vcpkg"
                        VCPKG_BINARY_SOURCES  = 'clear;x-aws,s3://vcpkg-cache/archives/,readwrite'
                        AWS_ACCESS_KEY_ID     = credentials('s4_access_key_id_vcpkg_cache')
                        AWS_SECRET_ACCESS_KEY = credentials('s4_secret_access_key_vcpkg_cache')
                        AWS_ENDPOINT_URL      = "https://s3.g.s4.mega.io"
                        BUILD_DIR = "build_dir"
                    }
                    steps{
                        dir(megachat_sources_workspace){
                            sh "echo Building MEGAchat"
                            sh "cmake --preset dev-unix -DCMAKE_BUILD_TYPE=Debug -DVCPKG_ROOT=${VCPKGPATH} ${BUILD_OPTIONS} -DCMAKE_VERBOSE_MAKEFILE=ON \
                            -S ${megachat_sources_workspace} -B ${megachat_sources_workspace}/${BUILD_DIR}"
                            sh "cmake --build ${megachat_sources_workspace}/${BUILD_DIR} -j5"
                        }
                    }
                    post {
                        failure {
                            script {
                                setCommitStatus('build_failure', ':red_circle: Build failed. Tests won`t run')
                            }
                            echo "Error: Build stage failed. Tests won't run."
                        }
                    }
                }
                stage('Run MEGAchat tests'){
                    environment {
                        MEGA_PWD0 = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD1 = credentials('MEGA_PWD_DEFAULT')
                        MEGA_PWD2 = credentials('MEGA_PWD_DEFAULT')
                        BUILD_DIR = "build_dir"
                    }
                    steps{
                        script {
                            def lockLabel = ''
                            if ("${APIURL_TO_TEST}" == 'https://g.api.mega.co.nz/') {
                                lockLabel = 'SDK_Concurrent_Test_Accounts'
                            } else  {
                                lockLabel = 'SDK_Concurrent_Test_Accounts_Staging'
                            }
                            lock(label: lockLabel, variable: 'ACCOUNTS_COMBINATION', quantity: 1, resourceSelectStrategy: "random", resource: null){
                                dir("${megachat_sources_workspace}"){
                                    timeout(time: "${CUSTOM_TIMEOUT}", unit: 'MINUTES') {
                                        script{
                                            env.MEGA_EMAIL0 = "${env.ACCOUNTS_COMBINATION}"
                                            echo "${env.ACCOUNTS_COMBINATION}"

                                        }
                                        sh """#!/bin/bash
                                            set -x
                                            ulimit -c unlimited
                                            if [ -z \"${TESTS_PARALLEL}\" ]; then
                                                # Sequential run
                                                ${env.BUILD_DIR}/tests/sdk_test/megachat_tests --USERAGENT:${env.USER_AGENT_TESTS_MEGACHAT} --APIURL:${APIURL_TO_TEST} ${GTEST_FILTER} ${GTEST_REPEAT} &
                                                pid=\$!
                                                wait \$pid || FAILED=1
                                            else
                                                # Parallel run
                                                ${env.BUILD_DIR}/tests/sdk_test/megachat_tests --USERAGENT:${env.USER_AGENT_TESTS_MEGACHAT} --APIURL:${APIURL_TO_TEST} ${GTEST_FILTER} ${GTEST_REPEAT} ${TESTS_PARALLEL} 2>&1 | tee tests.stdout
                                                [ \"\${PIPESTATUS[0]}\" != \"0\" ] && FAILED=1
                                            fi

                                            if [ -n "\$FAILED" ]; then
                                                if [ -z \"${TESTS_PARALLEL}\" ]; then
                                                    # Sequential run
                                                    coreFiles=\"test_pid_\$pid/core\"
                                                else
                                                    # Parallel run
                                                    procFailed=`grep \"<< PROCESS\" tests.stdout | sed 's/.*PID:\\([0-9]*\\).*/\\1/'`
                                                    if [ -n \"\$procFailed\" ]; then
                                                        for i in \$procFailed; do
                                                            coreFiles=\"\$coreFiles test_pid_\$i/core\"
                                                        done
                                                    fi
                                                fi
                                            fi

                                            if [ -n \"\$coreFiles\" ]; then
                                                maxTime=10
                                                startTime=`date +%s`
                                                coresProcessed=0
                                                coresTotal=`echo \$coreFiles | wc -w`
                                                # While there are pending cores
                                                while [ \$coresProcessed -lt \$coresTotal ] && [ \$( expr `date +%s` - \$startTime ) -lt \$maxTime ]; do
                                                    echo "Waiting for core dumps..."
                                                    sleep 1
                                                    for i in \$coreFiles; do
                                                        if [ -e \"\$i\" ] && [ -z \"\$( lsof \$i 2>/dev/null )\" ]; then
                                                            echo
                                                            echo
                                                            echo \"Processing core dump \$i :: \$(grep `echo \$i | sed 's#test_pid_\\([0-9].*\\)/core#\\1#'` tests.stdout)\"
                                                            echo thread apply all bt > backtrace
                                                            echo quit >> backtrace
                                                            gdb -q ${env.BUILD_DIR}/tests/sdk_test/megachat_tests \$i -x backtrace
                                                            tar rf core.tar \$i
                                                            coresProcessed=`expr \$coresProcessed + 1`
                                                            coreFiles=`echo \$coreFiles | sed -e \"s#\$i##\"`
                                                        fi
                                                    done
                                                done
                                                if [ -e core.tar ]; then
                                                    tar rf core.tar -C ${env.BUILD_DIR}/tests/sdk_test/ megachat_tests
                                                    gzip core.tar
                                                fi
                                            fi

                                            gzip -c test.log > test_${BUILD_ID}.log.gz || :
                                            rm test.log || :
                                            if [ ! -z "\$FAILED" ]; then
                                                false
                                            fi
                                        """
                                    }
                                }
                            }
                        }
                    }
                    post {
                        failure {
                            script {
                                setCommitStatus('tests_failure', ':warning: Build succeed. Tests failed')
                            }
                            echo 'Error: Test stage failed'
                        }
                    }
                }
            }
            post{
                always {
                    archiveArtifacts artifacts: 'test*.log*, core.tar.gz', fingerprint: true
                    deleteDir()
                }
            }
        }
    }
    post {
        success {
            updateGitlabCommitStatus(name: 'Build & test MEGAchat', state: 'success')
            addGitLabMRComment(comment: ":white_check_mark: ${currentBuild.projectName} :penguin: <b>MEGAchat</b> SUCCEEDED :muscle:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${COMMIT_ID}" )
        }
        unstable {
            updateGitlabCommitStatus(name: 'Build & test MEGAchat', state: 'failed')
            addGitLabMRComment(comment: ":interrobang: ${currentBuild.projectName} :penguin: <b>MEGAchat</b> UNSTABLE  :confused:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${COMMIT_ID}" )      
        }
        aborted {
            updateGitlabCommitStatus(name: 'Build & test MEGAchat', state: 'canceled')
            addGitLabMRComment(comment: ":interrobang: ${currentBuild.projectName} :penguin: <b>MEGAchat</b> ABORTED  :confused:<br/>Build results: [Jenkins [${currentBuild.displayName}]](${currentBuild.absoluteUrl})<br/>Commit: ${COMMIT_ID}" )
        }
    }
}
