#!/usr/bin/zx
import fs from 'fs'


// load config from first argument
console.log("Loading:", process.argv[3])
const config = JSON.parse(await $`cat ${process.argv[3]}`)
console.log('Config:', config)

const matrix = config.matrix
const allVariables = Object.keys(matrix)
const variables = Object.keys(matrix).filter(variable => variable !== 'SIMULATOR')

const recordOutput = config.recordOutput || false

// Create a list of all combinations of variables
let combinations = [{}]
for (const variable of variables) {
    const newCombinations = []
    for (const value of matrix[variable]) {
        for (const combination of combinations) {
            newCombinations.push({ ...combination, [variable]: value })
        }
    }
    combinations = newCombinations
}

console.log('Combinations:', combinations.length)

const matrixBinaryName = `${config.name}_${variables.map(variable => `${variable}_\${${variable}}`).join('_')}.riscv`

let workflow = `
stages:
    - benchmark

variables:
    GIT_DEPTH: "1"
`
for (const size of config.sizes) {
    workflow += `
${config.name}_${size}:
    stage: benchmark
    parallel:
        matrix:
            - ${allVariables.map(variable => `${variable}: ${JSON.stringify(matrix[variable])}`).join('\n              ')}
    image:
        name: quay.io/jonas_peeters/boom:${config.imageTag}
    tags:
        - AMD64
        - AppleSilicon
    script:
      - |
        echo "Run command: (set -o pipefail && time /opt/${size}BoomConfig +permissive +dramsim +dramsim_ini_dir=/opt/dramsim2_ini +max-cycles=1000000000 ${recordOutput ? '+verbose' : ''} +permissive-off /opt/pk ./binaries/${matrixBinaryName} </dev/null)"
        ls ./binaries/${matrixBinaryName}
      - bash -c "(set -o pipefail && time /opt/\${{ matrix.SIMULATOR }} +permissive +dramsim +dramsim_ini_dir=/opt/dramsim2_ini +max-cycles=1000000000 ${recordOutput ? '+verbose' : ''} +permissive-off /opt/pk ./binaries/${matrixBinaryName} </dev/null > >(tee -a ${matrixBinaryName}.out) 2> >(tee -a ${matrixBinaryName}.out >/dev/null))"
    ${recordOutput ? ` - |
        export TIMESTAMP=$(date +%Y%m%d_%H%M%S)
        mv ${matrixBinaryName}.out ${matrixBinaryName}_\${TIMESTAMP}.out
        curl -T ${matrixBinaryName}_\${TIMESTAMP}.out https://files.ham.peeters.page/upload/
        ` : ''
        }
`
}

const workflowFileName = `.gitlab-ci.yml`
fs.writeFileSync(workflowFileName, workflow)

await $`rm binaries/*`

for (const combination of combinations) {
    // Build the binary
    const $$ = $({
        verbose: false,
        shell: '/bin/bash',
        env: {
            RISCV: "/home/peeters/riscv/install/gnu-riscv-toolchain",
            PATH: "$RISCV/bin:$PATH",
            CC: "/home/peeters/riscv/install/gnu-riscv-toolchain/bin/riscv64-unknown-elf-clang",
            CXX: "/home/peeters/riscv/install/gnu-riscv-toolchain/bin/riscv64-unknown-elf-clang++",
        },
        quiet: true,
    })
    const ar = Object.entries(combination).map(([key, value]) => `-D${key}=${value}`)
    const outputName = `binaries/${config.name}_${Object.entries(combination).map(([key, value]) => `${key}_${value}`).join('_')}.riscv`
    console.log("Building:", outputName, "with", ar.join(' '))
    await $$`/home/peeters/riscv/install/gnu-riscv-toolchain/bin/riscv64-unknown-elf-clang++ --target=riscv64-unknown-elf -O2 -fno-common -fno-builtin-printf -Wall -march=rv64imafdc_zicond_zicntr_xbmis0p1 -mabi=lp64d -mcmodel=medlow -menable-experimental-extensions ${config.source} ${ar} -o ${outputName} -lc -fuse-ld=lld -lm -DWITH_PRINTF -g`
    await $$`/home/peeters/riscv/install/gnu-riscv-toolchain/bin/llvm-objdump -d -S ${outputName} > ${outputName}.asm`
}

if (process.argv[4] !== '--skip-commit') {
    // Commit the changes
    await $`git add .`
    await $`git commit -m "Add/update ${config.name} benchmark"`
    await $`git push`
}