/*
Master weekly (master-weekly):
- predefined-throughput-steps-i8g-tablets — us-east-1, versions: ['master'], labels: ['master-weekly'], all 4 sub tests
- All 4 microbenchmark jobs — us-east-1, ignore_versions: [], labels: ['master-weekly']

Master 3-weeks (master-3weeks):
- latency-650gb-during-rolling-upgrade-i8g-tablets — us-east-2, versions: ['master'], labels: ['master-3weeks'], mixed load
- latency-650gb-with-nemesis-i8g-tablets — eu-north-1, versions: ['master'], labels: ['master-3weeks'], mixed load

Master monthly (master-monthly):
- predefined-throughput-steps-i8g-vnodes — eu-west-2, versions: ['master'], labels: ['master-monthly'], all 4 sub tests
- latency-650gb-with-nemesis-i8g-vnodes — eu-north-1, versions: ['master'], labels: ['master-monthly'], all 3 sub tests (mixed, read, write)

< Scylla version 2025.3 (non-master, versions 2025.2, 2025.1, 2024.2, 2024.1):
- predefined-throughput-steps-vnodes — us-east-1, versions: ['2025.2', '2025.1', '2024.2', '2024.1'], all sub tests (read, mixed, disk_only)
- predefined-throughput-steps-write-vnodes — us-east-1, versions: ['2025.2', '2025.1', '2024.2', '2024.1']
- latency-650gb-with-nemesis — eu-west-2, versions: ['2025.2', '2025.1', '2024.2', '2024.1'], mixed load
- Microbenchmark jobs — us-east-1, ignore_versions: [] means they match all versions; labels: ['master-weekly'] only gates master trigger, non-master versions pass through
- predefined-throughput-steps-tablets — us-east-1, versions: ['2025.2', '2025.1'], all sub tests
- predefined-throughput-steps-write-tablets — us-east-1, versions: ['2025.2', '2025.1']
- latency-650gb-during-rolling-upgrade-tablets — eu-west-2, versions: ['2025.2', '2025.1'], mixed load
- latency-650gb-with-nemesis-tablets — eu-west-3, versions: ['2025.2', '2025.1'], read + mixed

>= Scylla version 2025.3 (non-master/release):
- predefined-throughput-steps-i8g-tablets — us-west-2, ignore_versions: ['2025.2', '2025.1', '2024.1', '2024.2', 'master'], all sub tests
- latency-650gb-during-rolling-upgrade-i8g-tablets — eu-west-2, ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'], mixed load
- latency-650gb-with-nemesis-i8g-tablets — eu-west-2, ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'], read + mixed
- predefined-throughput-steps-i8g-vnodes — eu-west-2, ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'], mixed only
- latency-650gb-with-nemesis-i8g-vnodes — eu-west-1, ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'], mixed only
*/

def isVersionIgnored(String version, List ignoreVersions) {
    return ignoreVersions.any { ver ->
        version?.trim() == ver || version?.trim().startsWith(ver + ".")
    }
}

def call(Map pipelineParams) {
    def builder = getJenkinsLabels("aws", "eu-west-1")
    pipeline {
        agent {
            label {
                   label builder.label
            }
        }
        environment {
            AWS_ACCESS_KEY_ID     = credentials('qa-aws-secret-key-id')
            AWS_SECRET_ACCESS_KEY = credentials('qa-aws-secret-access-key')
            SCT_BILLING_PROJECT = "${params.billing_project}"
        }

        parameters {
            string(name: 'scylla_version', defaultValue: '', description: 'Scylla version to test')
            string(name: 'base_versions', defaultValue: '', description: 'Base versions')
            string(name: 'new_scylla_repo', defaultValue: 'https://downloads.scylladb.com/unstable/scylla/master/deb/unified/latest/scylladb-master/scylla.list', description: 'New Scylla repo')
            booleanParam(name: 'use_job_throttling', defaultValue: true, description: 'if true, use job throttling to limit the number of concurrent builds')
            string(name: 'labels_selector', defaultValue: '', description: 'This parameter is used for trigger with Scylla master version only. It points how to trigger the test: daily, weekly ot once in 3 weeks. Expected values: master-3weeks OR master-weekly OR master-daily')
            string(defaultValue: '',
                   description: 'Actual user requesting job start, for automated job builds (e.g. through Argus)',
                   name: 'requested_by_user')
            choice(choices: getBillingProjectChoices(),
                   description: 'Billing project for the test run (dynamically fetched from finops repository)',
                   name: 'billing_project')
        }
        triggers {
            parameterizedCron (
                '''
                    0 8 * * * %scylla_version=master:latest;labels_selector=alternator-daily;requested_by_user=radoslawcybulski;billing_project=weekly performance regression
                    0 8 * * 6 %scylla_version=master:latest;labels_selector=alternator-weekly;requested_by_user=radoslawcybulski;billing_project=weekly performance regression
                    00 6 * * 0 %scylla_version=master:latest;labels_selector=master-weekly;requested_by_user=juliayakovlev;billing_project=weekly performance regression
                    0 23 */21 * * %scylla_version=master:latest;labels_selector=master-3weeks;requested_by_user=juliayakovlev;billing_project=weekly performance regression
                    0 6 1 * * %scylla_version=master:latest;labels_selector=master-monthly;requested_by_user=juliayakovlev;billing_project=weekly performance regression
                    13 6 8-14 * 2 %scylla_version=master:latest;labels_selector=gce-custom-monthly;requested_by_user=valerii.ponomarov;billing_project=weekly performance regression
                '''
            )
        }

        stages {
            stage('Get Scylla Version') {
                steps {
                    script {
                        def scylla_version = params.scylla_version?.trim()
                        def labels_selector = params.labels_selector?.trim()
                        if (scylla_version == "master:latest") {
                            scylla_version = "master"
                            if (!labels_selector) {
                                error "Labels selector is not set. Please provide one of a valid 'labels_selector' values: 'master-weekly' OR 'master-daily' OR 'master-3weeks'."
                            }


                        }
                        def testRegionMatrix = [
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-i8g-vnodes',
                                region: 'eu-west-2',
                                versions: ['master'],
                                pre_release: [],
                                sub_tests: ['"test_read_gradual_increase_load"', '"test_mixed_gradual_increase_load"', '"test_write_gradual_increase_load"', '"test_read_disk_only_gradual_increase_load"'],
                                labels: ['master-monthly'],
                                job_throttle_category: 'SCT-perf-eu-west-2-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-i8g-vnodes',
                                region: 'eu-west-2',
                                ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'],
                                pre_release: [],
                                sub_tests: ['"test_mixed_gradual_increase_load"'],
                                labels: [],
                                job_throttle_category: 'SCT-perf-eu-west-2-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-vnodes',
                                region: 'us-east-1',
                                versions: ['2025.2', '2025.1', '2024.2', '2024.1'],
                                pre_release: [],
                                sub_tests: ['"test_read_gradual_increase_load"', '"test_mixed_gradual_increase_load"', '"test_read_disk_only_gradual_increase_load"'],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-write-vnodes',
                                region: 'us-east-1',
                                versions: ['2025.2', '2025.1', '2024.2', '2024.1'],
                                pre_release: [],
                                sub_tests: ['"test_write_gradual_increase_load"'],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-during-rolling-upgrade',
                                region: 'eu-west-1',
                                ignore_versions: [],
                                pre_release: [],
                                sub_tests: [],
                                labels: [],
                                rolling_upgrade_test: true
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis',
                                region: 'eu-west-2',
                                versions: ['2025.2', '2025.1', '2024.2', '2024.1'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_nemesis"'],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis-rbno-disabled',
                                region: 'eu-west-3',
                                ignore_versions: [],
                                pre_release: [],
                                sub_tests: [],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis-i8g-vnodes',
                                region: 'eu-north-1',
                                versions: ['master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_nemesis"', '"test_latency_read_with_nemesis"', '"test_latency_write_with_nemesis"'],
                                labels: ['master-monthly'],
                                job_throttle_category: 'SCT-perf-eu-north-1-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis-i8g-vnodes',
                                region: 'eu-west-1',
                                ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_nemesis"'],
                                labels: [],
                                job_throttle_category: 'SCT-perf-eu-west-1-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-simple-query-weekly-microbenchmark_arm64',
                                region: 'us-east-1',
                                ignore_versions: [],
                                pre_release: [],
                                sub_tests: ['microbenchmark'],
                                labels: ['master-weekly'],
                                microbenchmark: true
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-simple-query-weekly-microbenchmark_arm64-write',
                                region: 'us-east-1',
                                ignore_versions: [],
                                pre_release: [],
                                sub_tests: ['microbenchmark'],
                                labels: ['master-weekly'],
                                microbenchmark: true
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-simple-query-weekly-microbenchmark_x86_64',
                                region: 'us-east-1',
                                ignore_versions: [],
                                pre_release: [],
                                sub_tests: ['microbenchmark'],
                                labels: ['master-weekly'],
                                microbenchmark: true
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-simple-query-weekly-microbenchmark_x86_64-write',
                                region: 'us-east-1',
                                ignore_versions: [],
                                pre_release: [],
                                sub_tests: ['microbenchmark'],
                                labels: ['master-weekly'],
                                microbenchmark: true
                            ],
                            [
                                job_name: 'scylla-master/perf-regression/perf-regression-predefined-throughput-steps-sanity-vnodes',
                                region: '',
                                versions: [],
                                pre_release: [],
                                sub_tests: [],
                                labels: ['master-daily']
                            ],
                            [
                                job_name: 'scylla-master/perf-regression/scylla-release-perf-regression-alternator',
                                region: 'eu-north-1',
                                versions: ['master'],
                                sub_tests: ['test_full'],
                                labels: ['alternator-weekly']
                            ],
                            [
                                job_name: 'scylla-master/perf-regression/latte-perf-regression-latency-steady-state-custom-d1-workload1-vnodes',
                                cloud_provider: 'gce',
                                region: 'us-east1',
                                use_job_throttling: false,
                                ignore_versions: ['2024.1', '2024.2'],
                                pre_release: ['rc1', 'rc3'],
                                sub_tests: ['"test_latency_steady_state"'],
                                labels: ['gce-custom-monthly']
                            ],
                            // Tablets
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-i8g-tablets',
                                region: 'us-east-1',
                                versions: ['master'],
                                pre_release: [],
                                sub_tests: ['"test_read_gradual_increase_load"', '"test_mixed_gradual_increase_load"', '"test_write_gradual_increase_load"', '"test_read_disk_only_gradual_increase_load"'],
                                labels: ['master-weekly'],
                                job_throttle_category: 'SCT-perf-us-east-1-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-i8g-tablets',
                                region: 'us-west-2',
                                ignore_versions: ['2025.2', '2025.1', '2024.1', '2024.2', 'master'],
                                pre_release: [],
                                sub_tests: ['"test_read_gradual_increase_load"', '"test_mixed_gradual_increase_load"', '"test_write_gradual_increase_load"', '"test_read_disk_only_gradual_increase_load"'],
                                labels: [],
                                job_throttle_category: 'SCT-perf-us-west-2-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-tablets',
                                region: 'us-east-1',
                                versions: ['2025.2', '2025.1'],
                                pre_release: [],
                                sub_tests: ['"test_read_gradual_increase_load"', '"test_mixed_gradual_increase_load"', '"test_read_disk_only_gradual_increase_load"'],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-predefined-throughput-steps-write-tablets',
                                region: 'us-east-1',
                                versions: ['2025.2', '2025.1'],
                                pre_release: [],
                                sub_tests: ['"test_write_gradual_increase_load"'],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-master/perf-regression/latte-perf-regression-latency-steady-state-custom-d1-workload1-tablets',
                                cloud_provider: 'gce',
                                region: 'us-east1',
                                use_job_throttling: false,
                                ignore_versions: ['2024.1', '2024.2'],
                                pre_release: ['rc1', 'rc3'],
                                sub_tests: ['"test_latency_steady_state"'],
                                labels: ['gce-custom-monthly']
                            ],
                            // One in 3 weeks
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-during-rolling-upgrade-tablets',
                                region: 'eu-west-2',
                                versions: ['2025.2', '2025.1'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_upgrade"'],
                                labels: [],
                                rolling_upgrade_test: true
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis-tablets',
                                region: 'eu-west-3',
                                versions: ['2025.2', '2025.1'],
                                pre_release: [],
                                sub_tests: ['"test_latency_read_with_nemesis"', '"test_latency_mixed_with_nemesis"'],
                                labels: []
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-during-rolling-upgrade-i8g-tablets',
                                region: 'us-east-2',
                                versions: ['master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_upgrade"'],
                                labels: ['master-3weeks'],
                                rolling_upgrade_test: true,
                                job_throttle_category: 'SCT-perf-us-east-2-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-during-rolling-upgrade-i8g-tablets',
                                region: 'eu-west-2',
                                ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_upgrade"'],
                                labels: [],
                                rolling_upgrade_test: true,
                                job_throttle_category: 'SCT-perf-eu-west-2-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis-i8g-tablets',
                                region: 'eu-north-1',
                                versions: ['master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_nemesis"'],
                                labels: ['master-3weeks'],
                                job_throttle_category: 'SCT-perf-eu-north-1-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-with-nemesis-i8g-tablets',
                                region: 'eu-west-2',
                                ignore_versions: ['2025.2', '2025.1', '2024.2', '2024.1', 'master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_read_with_nemesis"', '"test_latency_mixed_with_nemesis"'],
                                labels: [],
                                job_throttle_category: 'SCT-perf-eu-west-2-i8g',
                                arch: 'aarch64'
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-elasticity',
                                region: 'eu-north-1',
                                ignore_versions: ['2024.1', '2024.2', 'master'],
                                pre_release: [],
                                sub_tests: ['"test_latency_mixed_with_nemesis"', '"test_latency_write_with_nemesis"'],
                                labels: ['master-3weeks']
                            ],
                            [
                                job_name: 'scylla-enterprise/perf-regression/scylla-enterprise-perf-regression-latency-650gb-elasticity',
                                region: 'eu-north-1',
                                versions: [],
                                pre_release: [],
                                sub_tests: [],
                                labels: []
                            ],
                        ]
                        println("testRegionMatrix: $testRegionMatrix")
                        def jobs_names = testRegionMatrix*.job_name.toSet()
                        println("Jobs names: $jobs_names")
                        def image_names = [:]
                        if (scylla_version == "master") {
                            // Collect unique cloud_provider-arch combinations first
                            def unique_keys = [:]  // image_cache_key -> [cloud_provider, arch, region]
                            for (def entry in testRegionMatrix) {
                                String cloud_provider = entry.cloud_provider ?: 'aws'
                                String arch = entry.arch ?: 'x86_64'
                                String image_cache_key = "${cloud_provider}-${arch}".toString()
                                if (!unique_keys.containsKey(image_cache_key)) {
                                    String lookup_region = entry.region ?: 'us-east-1'
                                    unique_keys[image_cache_key] = [cloud_provider: cloud_provider, arch: arch, region: lookup_region]
                                }
                            }
                            def unique_keys_list = unique_keys.keySet().collect()  // copy to serializable ArrayList
                            println("Unique image keys to look up: ${unique_keys_list}")
                            // Lookup images once per unique combination
                            for (String image_cache_key in unique_keys_list) {
                                def params_map = unique_keys[image_cache_key]
                                def output = sh(script: "./docker/env/hydra.sh list-images -c ${params_map.cloud_provider} -r ${params_map.region} -a ${params_map.arch} -o json", returnStdout: true).trim()
                                println("Output from hydra list-images (arch: ${params_map.arch}): $output")
                                def image_name_json = output.split('\n')[-1].trim()
                                println("Image name json: $image_name_json")
                                if (!image_name_json) {
                                    error "Image name is empty. Please check the hydra.sh command output."
                                }
                                image_names[image_cache_key] = new groovy.json.JsonSlurperClassic().parseText(image_name_json).keySet()[0]
                                println("Image name for ${image_cache_key}: ${image_names[image_cache_key]}")
                            }
                        }
                        for (job_name in jobs_names) {
                            println("Job name: $job_name")
                            def version = null
                            def sub_tests = []
                            def region = null
                            def image_name_for_job = null
                            def rolling_upgrade_test = null
                            def microbenchmark = null
                            def job_throttle_category = null
                            def use_job_throttling_override = null
                            def job_arch = null
                            for (def entry in testRegionMatrix) {

                                if (entry.job_name == job_name) {
                                    def entry_version_matched = false
                                    if (entry.containsKey('ignore_versions')) {
                                        if (!isVersionIgnored(scylla_version, entry.ignore_versions)) {
                                            version = params.scylla_version
                                            entry_version_matched = true
                                        }
                                    } else {
                                        for (def ver in (entry.versions ?: [])) {
                                            if (scylla_version?.trim() == ver || scylla_version?.trim().startsWith(ver + ".")) {
                                                version = params.scylla_version
                                                entry_version_matched = true
                                            }
                                        }
                                    }
                                    if (entry_version_matched) {
                                        if (scylla_version == "master" && labels_selector && !(entry.labels.contains(labels_selector))) {
                                            println("Skipping job $job_name for labels_selector: $labels_selector")
                                            continue
                                        }
                                        // NOTE: Check that Scylla version matches specified 'pre-release' parts.
                                        //       Semver structure: <major> "." <minor> "." <patch> "-" <pre-release> "+" <build>
                                        if (!scylla_version?.startsWith("master") && entry.pre_release && !entry.pre_release.any { pr -> version.contains("-${pr}") }) {
                                            println("Skipping job $job_name because $version version doesn't match specified pre-releases: ${entry.pre_release}")
                                            continue
                                        }
                                        region = entry.region
                                        sub_tests = entry.sub_tests
                                        println("Found for job $job_name: region : $region, version: $version, sub_tests: $sub_tests")
                                        rolling_upgrade_test = entry.rolling_upgrade_test
                                        microbenchmark = entry.microbenchmark
                                        job_throttle_category = entry.job_throttle_category
                                        use_job_throttling_override = entry.containsKey('use_job_throttling') ? entry.use_job_throttling : null
                                        job_arch = entry.arch ?: 'x86_64'
                                        if (rolling_upgrade_test || microbenchmark) {
                                            image_name_for_job = null
                                        } else {
                                            def job_cloud_provider = entry.cloud_provider ?: 'aws'
                                            String job_image_cache_key = "${job_cloud_provider}-${job_arch}".toString()
                                            image_name_for_job = image_names[job_image_cache_key]
                                        }
                                    }
                                }
                            }
                            if (region && version && sub_tests) {
                                catchError(buildResult: 'FAILURE', stageResult: 'FAILURE') {
                                    println("Building job: $job_name with sub_test: ${sub_tests}, region: ${region}, image_name_for_job: ${image_name_for_job}, scylla_version: ${version}")
                                    println("Send to job: scylla_version: ${rolling_upgrade_test ? null : (image_name_for_job ? null : params.scylla_version)}; scylla_ami_id: ${image_name_for_job ? image_name_for_job : null}; new_scylla_repo: ${rolling_upgrade_test ? params.new_scylla_repo : null}")
                                        build job: job_name, wait: false, parameters: [
                                            string(name: 'scylla_version', value: rolling_upgrade_test ? null : (image_name_for_job ? null : params.scylla_version)),
                                            string(name: 'scylla_ami_id', value: image_name_for_job ? image_name_for_job : null),
                                            string(name: 'base_versions', value: rolling_upgrade_test ? params.base_versions : null),
                                            string(name: 'provision_type', value: 'on_demand'),
                                            string(name: 'new_scylla_repo', value: rolling_upgrade_test ? params.new_scylla_repo : null),
                                            booleanParam(name: 'use_job_throttling', value: use_job_throttling_override != null ? use_job_throttling_override : params.use_job_throttling),
                                            string(name: 'sub_tests', value: groovy.json.JsonOutput.toJson(sub_tests)),
                                            string(name: 'region', value: region),
                                            string(name: 'requested_by_user', value: params.requested_by_user),
                                            string(name: 'billing_project', value: params.billing_project),
                                            string(name: 'job_throttle_category', value: job_throttle_category)
                                        ]
                                    }
                                }
                            }
                        }
                    }
                }
        }
    }
}
