on:
  workflow_call:
    inputs:
      arch:
        type: string
        default: "64"
      benchmark:
        type: string
        default: "OFF"
      compiler:
        type: string
        default: "gcc"
      coverage:
        type: string
        default: "OFF"
      dev_mode:
        type: string
        default: "OFF"
      experimental:
        type: string
        default: "OFF"
      pool_dispatch:
        type: string
        default: "NO-pool"
      repeat:
        type: string
        default: "1"
      sanitize:
        type: string
        description: "sanitize option to use, 'address' or 'thread'"
      server_version:
        type: string
        description: "nats-server version to test with"
        default: "latest"
      streaming:
        type: string
        default: "ON"
      tls:
        type: string
        default: "TLS"
      type:
        type: string
        description: "Debug or Release."
        default: "Release"
      ubuntu_version:
        type: string
        description: "Ubuntu version to use, e.g. '20.04'"
        default: "latest"
      verbose_make_output:
        type: string
        default: "OFF"
      verbose_test_output:
        type: string
        default: "OFF"
      verify_host:
        type: string
        default: "verify_host"
      write_deadline:
        type: string
        default: "NO-write_deadline"

    secrets:
      CODECOV_TOKEN:
        description: "Codecov repo token"

permissions:
  contents: write # to comment on coverage.

defaults:
  run:
    shell: bash --noprofile --norc -x -eo pipefail {0}

jobs:
  do:
    runs-on: ubuntu-${{ inputs.ubuntu_version }}
    name: "${{ inputs.ubuntu_version }} - nats:${{ inputs.server_version }}"
    steps:
      - name: Checkout nats.c
        uses: actions/checkout@v4

      - name: "Checkout dependencies (nats.c.deps)"
        uses: actions/checkout@v4
        with:
          repository: nats-io/nats.c.deps
          path: deps

      # configure the cmake flags and NATS_... environment variables
      - id: cmake-flags
        name: Configure cmake flags
        env:
          flags: -DNATS_BUILD_ARCH=${{ inputs.arch }}
            -DCMAKE_BUILD_TYPE=${{ inputs.type }}
            -DNATS_BUILD_STREAMING=${{ inputs.streaming }}
            -DNATS_BUILD_USE_SODIUM=ON
            -DNATS_PROTOBUF_DIR=${{ github.workspace}}/deps/pbuf
            -DNATS_SODIUM_DIR=${{ github.workspace}}/deps/sodium
        run: |
          if [[ "${{ inputs.tls }}" == "TLS" ]]; then
            flags="$flags -DNATS_BUILD_WITH_TLS=ON"
            if [[ "${{ inputs.verify_host }}" == "verify_host" ]]; then
              flags="$flags -DNATS_BUILD_TLS_FORCE_HOST_VERIFY=ON"
            else
              flags="$flags -DNATS_BUILD_TLS_FORCE_HOST_VERIFY=OFF"
            fi
          else
            flags="$flags -DNATS_BUILD_WITH_TLS=OFF"
          fi
          if [[ "${{ inputs.coverage }}" == "ON" ]]; then
            flags="$flags -DNATS_COVERAGE=ON"
          fi
          if [[ "${{ inputs.dev_mode }}" == "ON" ]]; then
            flags="$flags -DDEV_MODE=ON"
          fi
          if [[ "${{ inputs.experimental }}" == "ON" ]]; then
            flags="$flags -DNATS_EXPERIMENTAL=ON"
          fi
          if [[ -n "${{ inputs.sanitize }}" ]]; then
            flags="$flags -DNATS_SANITIZE=ON -DCMAKE_C_FLAGS=-fsanitize=${{ inputs.sanitize }}"
          fi
          if [[ "${{ inputs.verbose_make_output }}" == "ON" ]]; then
            flags="$flags -DCMAKE_VERBOSE_MAKEFILE=ON"
          fi
          echo "flags=$flags" >> $GITHUB_OUTPUT

      - id: nats-vars
        name: Configure NATS_ environment variables
        run: |
          if [[ -n "${{ inputs.sanitize }}" ]]; then
            echo "NATS_TEST_VALGRIND=yes" >> $GITHUB_ENV
          fi
          if [[ "${{ inputs.pool_dispatch }}" == "pool" ]]; then
            echo "NATS_DEFAULT_TO_LIB_MSG_DELIVERY=yes" >> $GITHUB_ENV
          fi
          if [[ "${{ inputs.write_deadline }}" == "write_deadline" ]]; then
            echo "NATS_DEFAULT_LIB_WRITE_DEADLINE=2000" >> $GITHUB_ENV
          fi
          echo "CC=${{ inputs.compiler }}" >> $GITHUB_ENV

      # install build dependencies
      - name: Install ${{ inputs.compiler }} if needed
        if: startsWith(inputs.compiler, 'clang-') || startsWith(inputs.compiler, 'gcc-')
        run: |
          sudo apt-get -q update
          sudo apt-get -y install ${{ inputs.compiler }}

      # otherwise, configure cmake, build, archive and upload
      - name: CMake
        run: |
          mkdir -p build
          cd build
          cmake .. ${{ steps.cmake-flags.outputs.flags }}
          make rebuild_cache && make

      # testing

      - name: "Download nats-server version ${{ inputs.server_version }}"
        if: inputs.server_version
        working-directory: ./build
        run: |
          rel=${{ inputs.server_version }}
          if [ "$rel" = "latest" ]; then
            rel=$(curl -s https://api.github.com/repos/nats-io/nats-server/releases/latest | jq -r '.tag_name')
          fi
          if [ "$rel" != "${rel#v}" ] && wget https://github.com/nats-io/nats-server/releases/download/$rel/nats-server-$rel-linux-amd64.tar.gz; then
            tar -xzf nats-server-$rel-linux-amd64.tar.gz
            cp nats-server-$rel-linux-amd64/nats-server ../deps/nats-server/nats-server
          else
            for c in 1 2 3 4 5
            do
              echo "Attempt $c to download binary for main"
              rm -f ./nats-server
              curl -sf "https://binaries.nats.dev/nats-io/nats-server/v2@$rel" | PREFIX=. sh
              # We are sometimes getting nats-server of size 0. Make sure we have a
              # working nats-server by making sure we get a version number.
              v="$(./nats-server -v)"
              if [ "$v" != "" ]; then
                break
              fi
            done
            mv ./nats-server ../deps/nats-server/nats-server
          fi

      - name: "Test"
        if: inputs.benchmark == 'OFF'
        working-directory: ./build
        run: |
          export PATH=../deps/nats-server:../deps/nats-streaming-server:$PATH
          export NATS_TEST_SERVER_VERSION="$(nats-server -v)"
          flags=""
          ctest -L 'test' --timeout 60 --output-on-failure --repeat-until-fail ${{ inputs.repeat }}

      - name: Upload coverage reports to Codecov
        # PRs from external contributors fail: https://github.com/codecov/feedback/issues/301
        # Only upload coverage reports for PRs from the same repo (not forks)
        if: inputs.coverage == 'ON' && github.event.pull_request.head.repo.full_name == github.repository
        uses: codecov/codecov-action@v4
        with:
          fail_ci_if_error: true
          token: ${{ secrets.CODECOV_TOKEN }}
          # verbose: true

      - name: "Cache for base benchmark for ${{ github.event.pull_request.base.ref }}"
        id: cache-base-bench
        if: inputs.benchmark == 'ON' && github.event.pull_request.base.ref
        uses: actions/cache@v4
        with:
          key: bench-${{ github.event.pull_request.base.ref }}
          path: ./build/bench-${{ github.event.pull_request.base.ref }}.log

      - name: "Benchmark"
        if: inputs.benchmark == 'ON'
        working-directory: ./build
        run: |
          export PATH=../deps/nats-server:../deps/nats-streaming-server:$PATH
          export NATS_TEST_SERVER_VERSION="$(nats-server -v)"
          flags=""
          ctest -L 'bench' --timeout 600 -VV | tee bench.log

      - name: "Checkout nats.c for ${{ github.event.pull_request.base.ref }}"
        if: inputs.benchmark == 'ON' && github.event.pull_request.base.ref && steps.cache-base-bench.outputs.cache-hit != 'true'
        uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.base.ref }}
          clean: false

      - name: "Benchmark ${{ github.event.pull_request.base.ref }} for comparison"
        if: inputs.benchmark == 'ON' && github.event.pull_request.base.ref && steps.cache-base-bench.outputs.cache-hit != 'true'
        run: |
          mkdir -p build
          cd build
          rm -rf CMakeFiles CMakeCache.txt
          cmake .. ${{ steps.cmake-flags.outputs.flags }}
          make rebuild_cache && make
          export PATH=../deps/nats-server:../deps/nats-streaming-server:$PATH
          export NATS_TEST_SERVER_VERSION="$(nats-server -v)"
          flags=""
          ctest -L 'bench' --timeout 600 -VV | tee bench-${{ github.event.pull_request.base.ref }}.log

      - name: "Checkout HEAD ${{ github.event.pull_request.head.ref }}"
        if: inputs.benchmark == 'ON' && github.event.pull_request.head.ref && steps.cache-base-bench.outputs.cache-hit != 'true'
        uses: actions/checkout@v4
        with:
          clean: false

      - name: "Compare benchmark to ${{ github.event.pull_request.base.ref }}"
        if: inputs.benchmark == 'ON' && github.event.pull_request.base.ref
        run: |
          cd build
          go run ../test/diffstat_sub_async.go bench-${{ github.event.pull_request.base.ref }}.log bench.log
