/*
** Copyright (c) 2026 Valve Corporation
** Copyright (c) 2026 LunarG, Inc.
**
** Permission is hereby granted, free of charge, to any person obtaining a
** copy of this software and associated documentation files (the "Software"),
** to deal in the Software without restriction, including without limitation
** the rights to use, copy, modify, merge, publish, distribute, sublicense,
** and/or sell copies of the Software, and to permit persons to whom the
** Software is furnished to do so, subject to the following conditions:
**
** The above copyright notice and this permission notice shall be included in
** all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
** IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
** FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
** AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
** LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
** FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
** DEALINGS IN THE SOFTWARE.
*/

def extendedGitCommit = null

pipeline {
    agent none

    options {
        disableConcurrentBuilds(abortPrevious: true)
    }

    stages {
        stage('Per Commit Tests') {
            steps {
                script {
                    // different log rotator settings for dev vs PRs
                    def discarder = env.BRANCH_NAME == 'dev'
                        ? buildDiscarder(logRotator(
                            daysToKeepStr: '90',
                            artifactDaysToKeepStr: '14'
                        ))
                        : buildDiscarder(logRotator(
                            daysToKeepStr: '14',
                            artifactNumToKeepStr: '3'
                        ))
                    properties([discarder])

                    def tests

                    // Checkout and load on any available node
                    node {
                        def scmVars = checkout scm
                        extendedGitCommit = scmVars.GIT_COMMIT
                        def runJob = load 'ci/runJob.groovy'

                        tests = [
                            'Android Rel64': runJob.gfxrTestAndroid('Android R64', runJob.ReleaseMode, runJob.AndroidLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            // 'Android Dbg32': runJob.gfxrTestAndroid('Android D32', runJob.ReleaseMode, runJob.AndroidLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Linux Mesa Rel64': runJob.gfxrTestLinux('Linux Mesa Rel64', runJob.ReleaseMode, runJob.LinuxMesaLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Linux Mesa Dbg32': runJob.gfxrTestLinux('Linux Mesa Dbg32', runJob.ReleaseMode, runJob.LinuxMesaLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Linux Nnvidia Rel64': runJob.gfxrTestLinux('Linux Nvidia Rel64', runJob.ReleaseMode, runJob.LinuxNvidiaLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Linux Nnvidia Dbg32': runJob.gfxrTestLinux('Linux Nvidia Dbg32', runJob.ReleaseMode, runJob.LinuxNvidiaLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Mac': runJob.gfxrTestLinux('Mac', runJob.ReleaseMode, runJob.MacLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows AMD Rel64': runJob.gfxrTestWindows('Win AMD Rel64', runJob.ReleaseMode, runJob.WinAMDLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows AMD Dbg32': runJob.gfxrTestWindows('Win AMD Dbg32', runJob.ReleaseMode, runJob.WinAMDLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows Nvidia Rel64': runJob.gfxrTestWindows('Win Nvidia Rel64', runJob.ReleaseMode, runJob.WinNvidiaLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows Nvidia Dbg32': runJob.gfxrTestWindows('Win Nvidia Dbg32', runJob.ReleaseMode, runJob.WinNvidiaLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows11 AMD Rel64': runJob.gfxrTestWindows('Win11 AMD Rel64', runJob.ReleaseMode, runJob.Win11AMDLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 AMD Dbg32': runJob.gfxrTestWindows('Win11 AMD Dbg32', runJob.ReleaseMode, runJob.Win11AMDLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows11 ARM Rel64': runJob.gfxrTestWindows('Win11 ARM Rel64', runJob.ReleaseMode, runJob.Win11ARMLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 ARM Dbg64': runJob.gfxrTestWindows('Win11 ARM Dbg64', runJob.ReleaseMode, runJob.Win11ARMLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 AMD 9070 Rel64': runJob.gfxrTestWindows('Win11 AMD 9070 Rel64', runJob.ReleaseMode, runJob.Win11AMD9070Label, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 AMD 9070 Dbg32': runJob.gfxrTestWindows('Win11 AMD 9070 Dbg32', runJob.ReleaseMode, runJob.Win11AMD9070Label, runJob.Bit32, "commit-suite.json", scm.branches),
                            'Windows11 Nvidia 5080 Rel64': runJob.gfxrTestWindows('Win11 Nvidia 5080 Rel64', runJob.ReleaseMode, runJob.Win11Nvidia50XXLabel, runJob.Bit64, "commit-suite.json", scm.branches),
                            'Windows11 Nvidia 5080 Dbg32': runJob.gfxrTestWindows('Win11 Nvidia 5080 Dbg32', runJob.ReleaseMode, runJob.Win11Nvidia50XXLabel, runJob.Bit32, "commit-suite.json", scm.branches),
                        ]
                    }
                    // parallel runs OUTSIDE the node block - each branch allocates its own node
                    parallel tests
                }
            }
        }

        stage('Trigger Extended Tests') {
            when {
                branch 'dev'
            }

            steps {
                script {
                    if (!extendedGitCommit?.trim()) {
                        error('Unable to resolve commit SHA for extended pipeline trigger')
                    }

                    build job: 'gfxr-pipelines/gfxr-extended',
                          wait: false,
                          propagate: false,
                          quietPeriod: calculateQuietPeriod(),
                          parameters: [
                              string(name: 'GIT_COMMIT', value: extendedGitCommit)
                          ]
                }
            }
        }
    }

    post {
        failure {
            script {
                if (env.BRANCH_NAME == 'dev') {
                    node {
                        googlechatnotification(
                            url: 'id:Google-Chat-GFXR',
                            message: "Build failed: <${env.BUILD_URL}|${env.BRANCH_NAME} #${env.BUILD_NUMBER}>",
                            notifyFailure: false,
                        )
                    }
                }
            }
        }
    }
}

// extended should only be run between 8pm and midnight, only on weekdays
// this function will calculate the amount of time to wait until the next time extended should run
def calculateQuietPeriod() {
    def now = new Date()
    def hour = now.getHours()
    def dayOfWeek = now.getDay()  // 0=Sun, 1=Mon, ..., 6=Sat

    // In window (Mon-Fri 8pm-midnight): run immediately
    if (dayOfWeek >= 1 && dayOfWeek <= 5 && hour >= 20 && hour < 24) {
        return 0
    }

    // Calculate seconds until next 8pm Mon-Fri
    def target = now.clone()
    target.setHours(20)
    target.setMinutes(0)
    target.setSeconds(0)

    // If today is weekday and before 8pm, target is today
    if (dayOfWeek >= 1 && dayOfWeek <= 5 && hour < 20) {
        // target is today at 8pm, already set
    }
    // If weekend or after midnight, find next weekday
    else {
        target = target + 1  // tomorrow
        while (target.getDay() == 0 || target.getDay() == 6) {
            target = target + 1  // skip weekend
        }
    }

    return (int) ((target.getTime() - now.getTime()) / 1000)
}
