name: CI (build & test)

on:
  push:
    branches: [ master ]
  pull_request:
    types: [opened, synchronize, reopened]

concurrency:
  group: ci-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
  cancel-in-progress: true

jobs:
  # Emit a wider matrix on master pushes (adds macOS), narrow on PRs (saves minutes)
  setup:
    runs-on: ubuntu-latest
    outputs:
      matrix: ${{ steps.set-matrix.outputs.matrix }}
    steps:
      - id: set-matrix
        shell: bash
        run: |
          if [[ "${{ github.event_name }}" == "push" ]]; then
            echo 'matrix={"include":[{"os":"ubuntu-latest"},{"os":"windows-latest"},{"os":"macos-latest"},{"os":"macos-15-intel"}]}' >> "$GITHUB_OUTPUT"
          else
            echo 'matrix={"include":[{"os":"ubuntu-latest"},{"os":"windows-latest"}]}' >> "$GITHUB_OUTPUT"
          fi

  build:
    name: Gradle build on ${{ matrix.os }}
    needs: setup
    strategy:
      fail-fast: false
      matrix: ${{ fromJson(needs.setup.outputs.matrix) }}
    runs-on: ${{ matrix.os }}
    permissions:
      checks: write
      contents: read
    env:
      JAVA_TOOL_OPTIONS: >-
        -XX:+UseCompactObjectHeaders
        -XX:+UseStringDeduplication
      GRADLE_OPTS: -Dorg.gradle.daemon=false
    defaults:
      run:
        working-directory: de.peeeq.wurstscript

    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Setup Temurin JDK 25
        uses: actions/setup-java@v4
        with:
          distribution: temurin
          java-version: '25'
          cache: 'gradle'

      # Linux only: use a portable, pristine Temurin 25 for jlink
      - name: (Linux) Install portable Temurin 25
        if: runner.os == 'Linux'
        shell: bash
        run: |
          set -euo pipefail
          URL="https://github.com/adoptium/temurin25-binaries/releases/download/jdk-25%2B36/OpenJDK25U-jdk_x64_linux_hotspot_25_36.tar.gz"
          mkdir -p "$RUNNER_TEMP/temurin25"
          curl -fsSL "$URL" -o "$RUNNER_TEMP/temurin25/jdk.tar.gz"
          tar -xzf "$RUNNER_TEMP/temurin25/jdk.tar.gz" -C "$RUNNER_TEMP/temurin25"
          PORTABLE_JAVA_HOME="$(find "$RUNNER_TEMP/temurin25" -maxdepth 1 -type d -name 'jdk-25*' | head -n1)"
          echo "PORTABLE_JAVA_HOME=$PORTABLE_JAVA_HOME" >> "$GITHUB_ENV"
          echo "$PORTABLE_JAVA_HOME/bin" >> "$GITHUB_PATH"

      # Pin Gradle toolchain to the active JDK (portable on Linux, setup-java on Windows)
      - name: Pin Gradle toolchain
        shell: bash
        run: |
          ACTIVE_JAVA_HOME="${PORTABLE_JAVA_HOME:-$JAVA_HOME}"
          echo "JAVA_HOME=${ACTIVE_JAVA_HOME}" >> "$GITHUB_ENV"
          echo "${ACTIVE_JAVA_HOME}/bin" >> "$GITHUB_PATH"
          echo "org.gradle.java.installations.paths=${ACTIVE_JAVA_HOME}" >> gradle.properties
          echo "org.gradle.java.installations.auto-detect=false" >> gradle.properties

      - name: Show Java & jlink
        shell: bash
        run: |
          echo "JAVA_HOME=$JAVA_HOME"
          "$JAVA_HOME/bin/java" -version
          "$JAVA_HOME/bin/jlink" --version

      - name: Validate Gradle wrapper
        uses: gradle/actions/wrapper-validation@v4

      - name: Setup Gradle (cache)
        uses: gradle/actions/setup-gradle@v4

      # ---- FAIL FAST: package first (so jlink issues show immediately) ----
      - name: Package slim runtime (fail fast)
        shell: bash
        run: ./gradlew packageSlimCompilerDist --no-daemon --stacktrace

      - name: Prepare bundled Lua runtime (Linux)
        if: runner.os == 'Linux'
        shell: bash
        run: |
          if [[ -f src/test/resources/lua53 ]]; then
            chmod +x src/test/resources/lua53
          fi

      - name: Install Lua compiler (macOS)
        if: runner.os == 'macOS'
        env:
          HOMEBREW_NO_AUTO_UPDATE: '1'
        shell: bash
        run: brew install lua

      - name: Run tests
        shell: bash
        run: ./gradlew test --no-daemon --stacktrace

      - name: Report test results
        if: always()
        uses: mikepenz/action-junit-report@v4
        with:
          report_paths: de.peeeq.wurstscript/build/test-results/**/*.xml
          check_name: Test Results (${{ matrix.os }})
          fail_on_failure: false

      - name: Upload packaged artifact (per-OS)
        uses: actions/upload-artifact@v4
        with:
          name: wurst-compiler-${{ matrix.os }}
          path: |
            de.peeeq.wurstscript/build/releases/*.zip
            de.peeeq.wurstscript/build/releases/*.tar.gz
            de.peeeq.wurstscript/build/releases/*.sha256
          if-no-files-found: error
          retention-days: 7

  nightly_release:
    name: Nightly prerelease (master)
    needs: build
    if: github.ref == 'refs/heads/master' && github.event_name == 'push'
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Checkout (to update nightly tag)
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Move 'nightly' tag to this commit
        run: |
          git config user.name "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git tag -f nightly "$GITHUB_SHA"
          git push origin nightly --force

      - name: Download all packaged artifacts
        uses: actions/download-artifact@v4
        with:
          path: artifacts

      - name: Gather files (zip only)
        shell: bash
        run: |
          set -euo pipefail
          mkdir -p upload
          find artifacts -type f -name '*.zip' -print0 | xargs -0 -I{} cp "{}" upload/

      - name: Verify we have all platform zips
        shell: bash
        run: |
          shopt -s nullglob
          zips=(upload/*.zip)
          echo "Found ${#zips[@]} zip(s):"; ls -alh upload
          if (( ${#zips[@]} < 4 )); then
            echo "ERROR: expected Win + Linux + macOS arm64 + macOS x64 zips (got ${#zips[@]})."
            exit 1
          fi

      - name: Normalize nightly filenames
        shell: bash
        run: |
          set -euo pipefail
          for f in upload/*.zip; do
            base="$(basename "$f")"
            stem="${base%.zip}"
            new_stem="$(echo "$stem" | sed -E 's/-[0-9]+(\.[0-9]+)*-/-nightly-/' )"
            new="upload/${new_stem}.zip"
            if [[ "upload/$base" != "$new" ]]; then mv -f "upload/$base" "$new"; fi
          done
          echo "Renamed to:"; ls -alh upload

      - name: Publish Nightly Release (upload assets)
        uses: softprops/action-gh-release@v2
        with:
          tag_name: nightly
          prerelease: true
          draft: false
          make_latest: "false"
          name: Nightly Build (master)
          body: |
            Nightly build for the latest commit on `master`.
            This release is automatically updated on each push.
          files: upload/**
          fail_on_unmatched_files: false
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
