---
name: CI-Windows
permissions: {}

on:
  workflow_call:
    inputs:
      # Azure Artifact Signing account name
      azure_signing_account:
        required: false
        type: string
        default: ''
      # Azure Artifact Signing certificate profile name
      azure_signing_cert_profile:
        required: false
        type: string
        default: ''
      # Azure Artifact Signing account endpoint
      # e.g. https://<region>.codesigning.azure.net
      azure_signing_endpoint:
        required: false
        type: string
        default: ''
      publish_release:
        required: true
        type: string
      release_commit:
        required: true
        type: string
      release_version:
        required: true
        type: string
    secrets:
      # Azure Client ID (App Registration) for Artifact Signing
      AZURE_CLIENT_ID:
        required: false
      # Azure Client Secret for Artifact Signing
      AZURE_CLIENT_SECRET:
        required: false
      # Azure Tenant ID for Artifact Signing
      AZURE_TENANT_ID:
        required: false

jobs:
  build_windows:
    name: ${{ matrix.name }}
    runs-on: ${{ matrix.os }}
    defaults:
      run:
        shell: msys2 {0}
    permissions:
      contents: read
    strategy:
      fail-fast: false
      matrix:
        include:
          - name: Windows-AMD64
            os: windows-2022
            arch: x86_64
            msystem: ucrt64
            toolchain: ucrt-x86_64
          - name: Windows-ARM64
            os: windows-11-arm
            arch: aarch64
            msystem: clangarm64
            toolchain: clang-aarch64
    steps:
      - name: Checkout
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd  # v6.0.2
        with:
          submodules: recursive

      - name: Setup Dependencies Windows
        # if a dependency needs to be pinned, see https://github.com/LizardByte/build-deps/pull/186
        uses: msys2/setup-msys2@e9898307ac31d1a803454791be09ab9973336e1c  # v2.31.1
        with:
          msystem: ${{ matrix.msystem }}
          update: true
          install: >-
            wget

      - name: Update Windows dependencies
        env:
          # MSYSTEM is a built-in environment variable of MSYS2.
          # Do not use this environment variable name.
          MATRIX_MSYSTEM: ${{ matrix.msystem }}
          TOOLCHAIN: ${{ matrix.toolchain }}
        shell: msys2 {0}
        run: |
          # variables
          declare -A pinned_deps

          # dependencies
          dependencies=(
            "git"
            "mingw-w64-${TOOLCHAIN}-boost"
            "mingw-w64-${TOOLCHAIN}-cmake"
            "mingw-w64-${TOOLCHAIN}-cppwinrt"
            "mingw-w64-${TOOLCHAIN}-curl-winssl"
            "mingw-w64-${TOOLCHAIN}-gcc"
            "mingw-w64-${TOOLCHAIN}-graphviz"
            "mingw-w64-${TOOLCHAIN}-miniupnpc"
            "mingw-w64-${TOOLCHAIN}-nlohmann-json"
            "mingw-w64-${TOOLCHAIN}-onevpl"
            "mingw-w64-${TOOLCHAIN}-openssl"
            "mingw-w64-${TOOLCHAIN}-opus"
            "mingw-w64-${TOOLCHAIN}-toolchain"
          )

          if [[ "${MATRIX_MSYSTEM}" == "ucrt64" ]]; then
            dependencies+=(
              "mingw-w64-${TOOLCHAIN}-MinHook"
              "mingw-w64-${TOOLCHAIN}-nsis"
              "mingw-w64-${TOOLCHAIN}-nodejs"
            )
          fi

          # do not modify below this line

          ignore_packages=()
          tarballs=""
          for pkg in "${!pinned_deps[@]}"; do
            ignore_packages+=("${pkg}")
            version="${pinned_deps[$pkg]}"
            tarball="${pkg}-${version}-any.pkg.tar.zst"

            # download working version
            wget "https://repo.msys2.org/mingw/${MATRIX_MSYSTEM}/${tarball}"

            tarballs="${tarballs} ${tarball}"
          done

          # Create the ignore string for pacman
          ignore_list=$(IFS=,; echo "${ignore_packages[*]}")

          # install pinned dependencies
          if [ -n "${tarballs}" ]; then
            pacman -U --noconfirm "${tarballs}"
          fi

          # Only add --ignore if we have packages to ignore
          if [ -n "${ignore_list}" ]; then
            pacman -Syu --noconfirm --ignore="${ignore_list}" "${dependencies[@]}"
          else
            pacman -Syu --noconfirm "${dependencies[@]}"
          fi

      - name: Install Doxygen
        # GCC compiled doxygen has issues when running graphviz
        env:
          DOXYGEN_VERSION: "1.11.0"
        shell: pwsh
        run: |
          # Set version variables
          $doxy_ver = $env:DOXYGEN_VERSION
          $_doxy_ver = $doxy_ver.Replace(".", "_")

          # Download the Doxygen installer
          Invoke-WebRequest -Uri `
            "https://github.com/doxygen/doxygen/releases/download/Release_${_doxy_ver}/doxygen-${doxy_ver}-setup.exe" `
            -OutFile "doxygen-setup.exe"

          # Run the installer
          Start-Process `
            -FilePath .\doxygen-setup.exe `
            -ArgumentList `
              '/VERYSILENT' `
          -Wait `
          -NoNewWindow

          # Clean up
          Remove-Item -Path doxygen-setup.exe

      - name: Setup dotnet  # needed for wix
        uses: actions/setup-dotnet@c2fa09f4bde5ebb9d1777cf28262a3eb3db3ced7  # v5.2.0
        with:
          dotnet-version: '10.x'

      - name: Setup NodeJS
        # Clang compiled NodeJS has issues when running rollup webpack
        if: matrix.msystem != 'ucrt64'
        uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e  # v6.4.0
        with:
          node-version: 'lts/*'

      - name: NodeJS Path
        if: matrix.msystem != 'ucrt64'
        shell: pwsh
        run: |
          # get NodeJS PATH
          $NODEJS_BINARY_PATH = (Get-Command node).Source
          $NODEJS_PATH = Split-Path -Path "$NODEJS_BINARY_PATH" -Parent

          # setup environment variables
          echo "NODEJS_PATH=$NODEJS_PATH" >> $env:GITHUB_ENV

          # step output
          echo "nodejs-path=$NODEJS_PATH"
          echo "nodejs-path=$NODEJS_PATH" >> $env:GITHUB_OUTPUT

      - name: Setup python
        id: setup-python
        uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405  # v6.2.0
        with:
          python-version: '3.14'

      - name: Python Path
        id: python-path
        shell: msys2 {0}
        run: |
          # replace backslashes with double backslashes
          python_path=$(echo "${{ steps.setup-python.outputs.python-path }}" | sed 's/\\/\\\\/g')

          # step output
          echo "python-path=${python_path}"
          echo "python-path=${python_path}" >> "${GITHUB_OUTPUT}"

      - name: Build Windows
        shell: msys2 {0}
        env:
          # MSYSTEM is a built-in environment variable of MSYS2.
          # Do not use this environment variable name.
          MATRIX_MSYSTEM: ${{ matrix.msystem }}
          BRANCH: ${{ github.head_ref || github.ref_name }}
          BUILD_VERSION: ${{ inputs.release_version }}
          COMMIT: ${{ inputs.release_commit }}
        run: |
          # setup NodeJS PATH
          if [[ "${MATRIX_MSYSTEM}" != "ucrt64" ]]; then
            NODEJS_PATH=$(cygpath "$NODEJS_PATH")
            export PATH="$PATH:$NODEJS_PATH"
          fi

          mkdir -p build
          cmake \
            -B build \
            -G Ninja \
            -S . \
            -DBUILD_WERROR=ON \
            -DCMAKE_BUILD_TYPE=RelWithDebInfo \
            -DSUNSHINE_ASSETS_DIR=assets \
            -DSUNSHINE_PUBLISHER_NAME="${GITHUB_REPOSITORY_OWNER}" \
            -DSUNSHINE_PUBLISHER_WEBSITE="https://app.lizardbyte.dev" \
            -DSUNSHINE_PUBLISHER_ISSUE_URL="https://app.lizardbyte.dev/support"
          echo "::add-matcher::.github/matchers/gcc.json"
          ninja -C build
          echo "::remove-matcher owner=gcc::"

      - name: Sign Windows executables
        # ARM64 is not currently supported, see https://github.com/Azure/artifact-signing-action/issues/92
        if: inputs.publish_release == 'true' && inputs.azure_signing_account != '' && matrix.name != 'Windows-ARM64'
        uses: azure/trusted-signing-action@b443cf8ea4124818d2ea9f043cba29fc3ec47b16  # v1.2.0
        with:
          azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
          azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
          azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          certificate-profile-name: ${{ inputs.azure_signing_cert_profile }}
          endpoint: ${{ inputs.azure_signing_endpoint }}
          files: |
            ${{ github.workspace }}/build/sunshine.exe
            ${{ github.workspace }}/build/tools/audio-info.exe
            ${{ github.workspace }}/build/tools/dxgi-info.exe
            ${{ github.workspace }}/build/tools/sunshinesvc.exe
          files-folder: src_assets/windows
          files-folder-filter: ps1
          files-folder-recurse: true
          signing-account-name: ${{ inputs.azure_signing_account }}

      - name: Package Windows
        shell: msys2 {0}
        run: |
          mkdir -p artifacts
          cd build

          # package
          cpack -G NSIS
          cpack -G WIX
          cpack -G ZIP

          # move
          mv ./cpack_artifacts/Sunshine.exe ../artifacts/Sunshine-${{ matrix.name }}-installer.exe
          mv ./cpack_artifacts/Sunshine.msi ../artifacts/Sunshine-${{ matrix.name }}-installer.msi
          mv ./cpack_artifacts/Sunshine.zip ../artifacts/Sunshine-${{ matrix.name }}-portable.zip

      - name: Sign Windows installers
        # ARM64 is not currently supported, see https://github.com/Azure/artifact-signing-action/issues/92
        if: inputs.publish_release == 'true' && inputs.azure_signing_account != '' && matrix.name != 'Windows-ARM64'
        uses: azure/trusted-signing-action@b443cf8ea4124818d2ea9f043cba29fc3ec47b16  # v1.2.0
        with:
          azure-client-id: ${{ secrets.AZURE_CLIENT_ID }}
          azure-client-secret: ${{ secrets.AZURE_CLIENT_SECRET }}
          azure-tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          certificate-profile-name: ${{ inputs.azure_signing_cert_profile }}
          endpoint: ${{ inputs.azure_signing_endpoint }}
          files-folder: artifacts
          files-folder-filter: exe,msi
          files-folder-recurse: false
          signing-account-name: ${{ inputs.azure_signing_account }}

      - name: Debug nsis
        if: always()
        shell: msys2 {0}
        run: cat ./build/cpack_artifacts/_CPack_Packages/win64/NSIS/NSISOutput.log || true

      - name: Debug wix
        if: always()
        shell: msys2 {0}
        run: cat ./build/cpack_artifacts/_CPack_Packages/win64/WIX/wix.log || true

      - name: Run tests
        id: test
        shell: msys2 {0}
        working-directory: build/tests
        run: ./test_sunshine.exe --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')
        shell: msys2 {0}
        working-directory: build
        run: |
          ${{ steps.python-path.outputs.python-path }} -m pip install "..[test]"
          ${{ steps.python-path.outputs.python-path }} -m gcovr . -r ../src \
            --exclude-noncode-lines \
            --exclude-throw-branches \
            --exclude-unreachable-branches \
            --verbose \
            --xml-pretty \
            -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: Package Windows Debug Info
        shell: pwsh
        working-directory: build
        run: |
          # use .dbg file extension for binaries to avoid confusion with real packages
          Get-ChildItem -File -Recurse | `
            % { Rename-Item -Path $_.PSPath -NewName $_.Name.Replace(".exe",".dbg") }

          # save the binaries with debug info
          7z -r `
            "-xr!CMakeFiles" `
            "-xr!cpack_artifacts" `
            a "../artifacts/Sunshine-${{ matrix.name }}-debuginfo.7z" "*.dbg"

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