---
name: CI-macOS
permissions: {}

on:
  workflow_call:
    inputs:
      publish_release:
        required: true
        type: string
      release_commit:
        required: true
        type: string
      release_version:
        required: true
        type: string
    secrets:
      # email address
      APPLE_ID:
        required: false
      # 10-character Team ID
      APPLE_TEAM_ID:
        required: false
      # app-specific password in APPLE_ID's account that must be named "notarytool"
      # https://support.apple.com/en-us/102654
      APPLE_NOTARYTOOL_PASSWORD:
        required: false
      # Developer ID Application: Full Name (TEAMIDHERE)
      APPLE_CODESIGN_IDENTITY:
        required: false
      # pkcs12 export from Xcode in base64
      APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64:
        required: false
      # pkcs12 password added by Xcode export
      APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD:
        required: false

env:
  BRANCH: ${{ github.head_ref || github.ref_name }}
  BUILD_VERSION: ${{ inputs.release_version }}
  COMMIT: ${{ inputs.release_commit }}
  MACOSX_DEPLOYMENT_TARGET: 14.2

jobs:
  build_dmg:
    name: ${{ matrix.name }}
    permissions:
      contents: read
    runs-on: ${{ matrix.os }}
    outputs:
      notarytool_submission_id_arm64: ${{ steps.notarize_submit.outputs.submission_id_arm64 }}
      notarytool_submission_id_x86_64: ${{ steps.notarize_submit.outputs.submission_id_x86_64 }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: "macos-14"
            name: "macOS-arm64"
            arch: "arm64"
          - os: "macos-15-intel"
            name: "macOS-x86_64"
            arch: "x86_64"
    steps:
      - name: Install Apple certificate
        uses: apple-actions/import-codesign-certs@5142e029c445c10ffc7149d172e540235a065466  # v7.0.0
        if: inputs.publish_release == 'true'
        with:
          p12-file-base64: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64 }}
          p12-password: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD }}

      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2
        with:
          submodules: recursive

      - name: Install dependencies
        timeout-minutes: 5
        run: |
          brew install --force \
            cmake \
            doxygen \
            graphviz \
            node \
            pkgconf \
            icu4c@78 \
            miniupnpc \
            openssl@3 \
            opus

      - name: Configure
        env:
          APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
        run: |
          mkdir -p build
          cmake \
            -B build \
            -S . \
            -DBUILD_WERROR=ON \
            -DCMAKE_BUILD_TYPE=Release \
            -DOPENSSL_ROOT_DIR="$(brew --prefix openssl@3 2>/dev/null)" \
            -DOpus_ROOT_DIR="$(brew --prefix opus 2>/dev/null)" \
            -DSUNSHINE_PUBLISHER_NAME="${GITHUB_REPOSITORY_OWNER}" \
            -DSUNSHINE_PUBLISHER_WEBSITE="https://app.lizardbyte.dev" \
            -DSUNSHINE_PUBLISHER_ISSUE_URL="https://app.lizardbyte.dev/support" \
            -DAPPLE_CODESIGN_IDENTITY="${APPLE_CODESIGN_IDENTITY}"

      - name: Build
        run: |
          echo "::add-matcher::.github/matchers/gcc.json"
          cmake --build build -j "$(sysctl -n hw.ncpu)"
          echo "::remove-matcher owner=gcc::"

      - name: Package DMG
        env:
          APPLE_CODESIGN_IDENTITY: ${{ secrets.APPLE_CODESIGN_IDENTITY }}
          MATRIX_NAME: ${{ matrix.name }}
          SHOULD_SIGN: ${{ inputs.publish_release }}
        run: |
          # build DMG and sign everything (see cmake/packaging/macos.cmake)
          # cpack can rarely fail with "hdiutil: create failed - Resource busy"
          # so let's allow 1 retry
          if ! cpack -G DragNDrop --config build/CPackConfig.cmake; then
            echo "cpack failed, retrying once with verbose..."
            if ! cpack -G DragNDrop --config build/CPackConfig.cmake --verbose; then
              echo "cpack failed again. Aborting."
              exit 1
            fi
          fi

          mkdir -p artifacts
          cp "build/cpack_artifacts/Sunshine.dmg" "artifacts/Sunshine-${MATRIX_NAME}.dmg"

      - name: Submit for notarization
        id: notarize_submit
        if: inputs.publish_release == 'true'
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          APPLE_NOTARYTOOL_PASSWORD: ${{ secrets.APPLE_NOTARYTOOL_PASSWORD }}
          MATRIX_ARCH: ${{ matrix.arch }}
        run: |
          # Notarizing allows the signed .app to run on any Mac with no prompts.
          # If you don't notarize, users must jump through the "Open Anyway" hoop as well as run
          # `xattr -cr /Applications/Sunshine.app` to remove quarantine.
          if [[ -n "${APPLE_NOTARYTOOL_PASSWORD}" ]]; then
            submission_id=$(xcrun notarytool submit build/cpack_artifacts/Sunshine.dmg \
              --apple-id "${APPLE_ID}" \
              --team-id "${APPLE_TEAM_ID}" \
              --password "${APPLE_NOTARYTOOL_PASSWORD}" \
              --output-format json \
              | jq -r '.id')
            echo "Submission ID: ${submission_id}"
            echo "submission_id_${MATRIX_ARCH}=${submission_id}" >> "${GITHUB_OUTPUT}"
          fi

      - name: Test
        id: test
        working-directory: build/tests
        run: ./test_sunshine --gtest_color=yes --gtest_output=xml:test_results.xml

      - name: Generate gcov report
        id: test_report
        # any except canceled or skipped
        if: >-
          always() &&
          (steps.test.outcome == 'success' || steps.test.outcome == 'failure')
        working-directory: build
        run: |
          python -m pip install "..[test]"
          python -m gcovr . -r ../src \
            --exclude-noncode-lines \
            --exclude-throw-branches \
            --exclude-unreachable-branches \
            --xml-pretty \
            -j "$(sysctl -n hw.ncpu)" \
            -o coverage.xml

      - name: Upload coverage artifact
        if: >-
          always() &&
          (steps.test_report.outcome == 'success')
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a  # v7.0.1
        with:
          name: coverage-${{ matrix.name }}
          path: |
            build/coverage.xml
            build/tests/test_results.xml
          if-no-files-found: error

      - name: Set artifact prefix
        id: artifact_prefix
        env:
          INPUTS_PUBLISH_RELEASE: ${{ inputs.publish_release }}
        run: |
          if [[ "${INPUTS_PUBLISH_RELEASE}" == "true" ]]; then
            echo "prefix=unsigned" >> "${GITHUB_OUTPUT}"
          else
            echo "prefix=build" >> "${GITHUB_OUTPUT}"
          fi

      - name: Upload Artifacts
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a  # v7.0.1
        with:
          name: ${{ steps.artifact_prefix.outputs.prefix }}-${{ matrix.name }}
          path: artifacts/
          if-no-files-found: error

  notarize_dmg:
    name: Notarize ${{ matrix.name }}
    needs: build_dmg
    if: inputs.publish_release == 'true'
    permissions:
      contents: read
    runs-on: ${{ matrix.os }}
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: "macos-14"
            name: "macOS-arm64"
            arch: "arm64"
          - os: "macos-15-intel"
            name: "macOS-x86_64"
            arch: "x86_64"
    steps:
      - name: Install Apple certificate
        uses: apple-actions/import-codesign-certs@5142e029c445c10ffc7149d172e540235a065466  # v7.0.0
        with:
          p12-file-base64: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_BASE64 }}
          p12-password: ${{ secrets.APPLE_DEVELOPER_ID_APPLICATION_CERTIFICATE_P12_PASSWORD }}

      - name: Download DMG artifact
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c  # v8.0.1
        with:
          name: unsigned-${{ matrix.name }}
          path: artifacts

      - name: Wait for notarization and staple
        env:
          APPLE_ID: ${{ secrets.APPLE_ID }}
          APPLE_TEAM_ID: ${{ secrets.APPLE_TEAM_ID }}
          APPLE_NOTARYTOOL_PASSWORD: ${{ secrets.APPLE_NOTARYTOOL_PASSWORD }}
          MATRIX_NAME: ${{ matrix.name }}
          SUBMISSION_ID: ${{ matrix.arch == 'arm64'
            && needs.build_dmg.outputs.notarytool_submission_id_arm64
            || needs.build_dmg.outputs.notarytool_submission_id_x86_64 }}
        run: |
          if [[ -z "${SUBMISSION_ID}" ]]; then
            echo "No submission ID found; skipping notarization wait."
            exit 0
          fi

          echo "Polling notarization status for submission: ${SUBMISSION_ID}"
          while true; do
            status=$(xcrun notarytool info "${SUBMISSION_ID}" \
              --apple-id "${APPLE_ID}" \
              --team-id "${APPLE_TEAM_ID}" \
              --password "${APPLE_NOTARYTOOL_PASSWORD}" \
              --output-format json \
              | jq -r '.status')
            echo "Current status: ${status}"
            if [[ "${status}" == "Accepted" ]]; then
              echo "Notarization accepted."
              break
            elif [[ "${status}" == "Invalid" || "${status}" == "Rejected" ]]; then
              echo "Notarization failed with status: ${status}"
              # Print the full log for debugging
              xcrun notarytool log "${SUBMISSION_ID}" \
                --apple-id "${APPLE_ID}" \
                --team-id "${APPLE_TEAM_ID}" \
                --password "${APPLE_NOTARYTOOL_PASSWORD}"
              exit 1
            fi
            echo "Status is '${status}', waiting 30 seconds before retrying..."
            sleep 30
          done

          xcrun stapler staple -v "artifacts/Sunshine-${MATRIX_NAME}.dmg"

      - name: Upload stapled artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a  # v7.0.1
        with:
          name: build-${{ matrix.name }}
          path: artifacts/
          if-no-files-found: error
