# SPDX-FileCopyrightText: 2024 shadPS4 Emulator Project
# SPDX-License-Identifier: GPL-2.0-or-later

name: Build and Release

on: [push, pull_request]

concurrency:
  group: ci-${{ github.event_name }}-${{ github.ref }}
  cancel-in-progress: ${{ github.event_name == 'push' }}

env:
  BUILD_TYPE: Release

jobs:
  reuse:
    runs-on: ubuntu-latest
    continue-on-error: true
    steps:
    - uses: actions/checkout@v4
    - uses: fsfe/reuse-action@v5

  clang-format:
    runs-on: ubuntu-latest
    continue-on-error: true
    steps:
    - uses: actions/checkout@v4
      with:
        fetch-depth: 0
    - name: Install
      run: |
        wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
        sudo add-apt-repository 'deb http://apt.llvm.org/jammy/ llvm-toolchain-jammy-18 main'
        sudo apt update
        sudo apt install clang-format-18
    - name: Build
      env:
        COMMIT_RANGE: ${{ github.event.pull_request.base.sha }}..${{ github.event.pull_request.head.sha }}
      run: ./.ci/clang-format.sh
      
  get-info:
    runs-on: ubuntu-latest
    outputs:
      date: ${{ steps.vars.outputs.date }}
      shorthash: ${{ steps.vars.outputs.shorthash }}
      fullhash: ${{ steps.vars.outputs.fullhash }}
    steps:
    - uses: actions/checkout@v4
    - name: Get date and git hash
      id: vars
      run: |
        echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_ENV
        echo "shorthash=$(git rev-parse --short HEAD)" >> $GITHUB_ENV
        echo "fullhash=$(git rev-parse HEAD)" >> $GITHUB_ENV
        echo "date=$(date +'%Y-%m-%d')" >> $GITHUB_OUTPUT
        echo "shorthash=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
        echo "fullhash=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT

  windows-sdl:
    runs-on: windows-latest
    needs: get-info
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Cache CMake Configuration
      uses: actions/cache@v4
      env:
          cache-name: ${{ runner.os }}-sdl-ninja-cache-cmake-configuration
      with:
          path: | 
            ${{github.workspace}}/build
          key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
          restore-keys: |
            ${{ env.cache-name }}-

    - name: Cache CMake Build
      uses: hendrikmuhs/ccache-action@v1.2.14
      env:
          cache-name: ${{ runner.os }}-sdl-cache-cmake-build
      with:
        append-timestamp: false
        key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}

    - name: Setup VS Environment
      uses: ilammy/msvc-dev-cmd@v1.13.0
      with:
        arch: amd64

    - name: Configure CMake
      run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $env:NUMBER_OF_PROCESSORS

    - name: Upload Windows SDL artifact
      uses: actions/upload-artifact@v4
      with:
        name: shadps4-win64-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: ${{github.workspace}}/build/shadPS4.exe

  windows-qt:
    runs-on: windows-latest
    needs: get-info
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Setup Qt
      uses: jurplel/install-qt-action@v4
      with:
        version: 6.7.3
        host: windows
        target: desktop
        arch: win64_msvc2019_64
        archives: qtbase qttools
        modules: qtmultimedia

    - name: Cache CMake Configuration
      uses: actions/cache@v4
      env:
          cache-name: ${{ runner.os }}-qt-ninja-cache-cmake-configuration
      with:
          path: | 
            ${{github.workspace}}/build
          key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
          restore-keys: |
            ${{ env.cache-name }}-

    - name: Cache CMake Build
      uses: hendrikmuhs/ccache-action@v1.2.14
      env:
          cache-name: ${{ runner.os }}-qt-cache-cmake-build
      with:
        append-timestamp: false
        key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}

    - name: Setup VS Environment
      uses: ilammy/msvc-dev-cmd@v1.13.0
      with:
        arch: amd64

    - name: Configure CMake
      run: cmake --fresh -G Ninja -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $env:NUMBER_OF_PROCESSORS

    - name: Deploy and Package
      run: |
        mkdir upload
        move build/shadPS4.exe upload
        windeployqt --no-compiler-runtime --no-system-d3d-compiler --no-system-dxc-compiler --dir upload upload/shadPS4.exe
        Compress-Archive -Path upload/* -DestinationPath shadps4-win64-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}.zip

    - name: Upload Windows Qt artifact
      uses: actions/upload-artifact@v4
      with:
        name: shadps4-win64-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: upload/

  macos-sdl:
    runs-on: macos-15
    needs: get-info
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Setup latest Xcode
      uses: maxim-lobanov/setup-xcode@v1
      with:
        xcode-version: latest

    - name: Cache CMake Configuration
      uses: actions/cache@v4 
      env: 
          cache-name: ${{ runner.os }}-sdl-cache-cmake-configuration
      with: 
          path: |  
            ${{github.workspace}}/build 
          key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} 
          restore-keys: | 
            ${{ env.cache-name }}- 

    - name: Cache CMake Build
      uses: hendrikmuhs/ccache-action@v1.2.14
      env:
          cache-name: ${{runner.os}}-sdl-cache-cmake-build
      with:
        append-timestamp: false
        create-symlink: true
        key: ${{env.cache-name}}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
        variant: sccache

    - name: Configure CMake
      run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64 -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)

    - name: Package and Upload macOS SDL artifact
      run: |
        mkdir upload
        mv ${{github.workspace}}/build/shadps4 upload
        cp ${{github.workspace}}/build/externals/MoltenVK/libMoltenVK.dylib upload
        tar cf shadps4-macos-sdl.tar.gz -C upload .
    - uses: actions/upload-artifact@v4
      with:
        name: shadps4-macos-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: shadps4-macos-sdl.tar.gz

  macos-qt:
    runs-on: macos-15
    needs: get-info
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Setup latest Xcode
      uses: maxim-lobanov/setup-xcode@v1
      with:
        xcode-version: latest

    - name: Setup Qt
      uses: jurplel/install-qt-action@v4
      with:
        version: 6.7.3
        host: mac
        target: desktop
        arch: clang_64
        archives: qtbase qttools
        modules: qtmultimedia
        
    - name: Cache CMake Configuration
      uses: actions/cache@v4 
      env: 
          cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
      with: 
          path: |  
            ${{github.workspace}}/build 
          key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} 
          restore-keys: | 
            ${{ env.cache-name }}- 

    - name: Cache CMake Build
      uses: hendrikmuhs/ccache-action@v1.2.14
      env:
          cache-name: ${{runner.os}}-qt-cache-cmake-build
      with:
        append-timestamp: false
        create-symlink: true
        key: ${{env.cache-name}}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}
        variant: sccache

    - name: Configure CMake
      run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_OSX_ARCHITECTURES=x86_64 -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER_LAUNCHER=sccache -DCMAKE_CXX_COMPILER_LAUNCHER=sccache

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(sysctl -n hw.ncpu)

    - name: Package and Upload macOS Qt artifact
      run: |
        mkdir upload
        mv ${{github.workspace}}/build/shadps4.app upload
        macdeployqt upload/shadps4.app
        tar cf shadps4-macos-qt.tar.gz -C upload .
    - uses: actions/upload-artifact@v4
      with:
        name: shadps4-macos-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: shadps4-macos-qt.tar.gz

  linux-sdl:
    runs-on: ubuntu-24.04
    needs: get-info
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Install dependencies
      run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential libasound2-dev libpulse-dev libopenal-dev libudev-dev

    - name: Cache CMake Configuration
      uses: actions/cache@v4 
      env: 
          cache-name: ${{ runner.os }}-sdl-cache-cmake-configuration
      with: 
          path: |  
            ${{github.workspace}}/build 
          key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} 
          restore-keys: | 
            ${{ env.cache-name }}- 

    - name: Cache CMake Build
      uses: hendrikmuhs/ccache-action@v1.2.14
      env:
          cache-name: ${{ runner.os }}-sdl-cache-cmake-build
      with:
        append-timestamp: false
        key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}

    - name: Configure CMake
      run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)
  
    - name: Package and Upload Linux(ubuntu64) SDL artifact 
      run: |
        ls -la ${{ github.workspace }}/build/shadps4
    
    - uses: actions/upload-artifact@v4
      with:
        name: shadps4-ubuntu64-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: ${{ github.workspace }}/build/shadps4

    - name: Run AppImage packaging script
      run:  ./.github/linux-appimage-sdl.sh
      
    - name: Package and Upload Linux SDL artifact
      run: |
        tar cf shadps4-linux-sdl.tar.gz -C ${{github.workspace}}/build shadps4
    - uses: actions/upload-artifact@v4
      with:
        name: shadps4-linux-sdl-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: Shadps4-sdl.AppImage

  linux-qt:
    runs-on: ubuntu-24.04
    needs: get-info
    steps:
    - uses: actions/checkout@v4
      with:
        submodules: recursive

    - name: Install dependencies
      run: sudo apt-get update && sudo apt install -y libx11-dev libxext-dev libwayland-dev libdecor-0-dev libxkbcommon-dev libglfw3-dev libgles2-mesa-dev libfuse2 clang build-essential qt6-base-dev qt6-tools-dev qt6-multimedia-dev libasound2-dev libpulse-dev libopenal-dev libudev-dev

    - name: Cache CMake Configuration
      uses: actions/cache@v4 
      env: 
          cache-name: ${{ runner.os }}-qt-cache-cmake-configuration
      with: 
          path: |  
            ${{github.workspace}}/build 
          key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }} 
          restore-keys: | 
            ${{ env.cache-name }}- 

    - name: Cache CMake Build
      uses: hendrikmuhs/ccache-action@v1.2.14
      env:
          cache-name: ${{ runner.os }}-qt-cache-cmake-build
      with:
        append-timestamp: false
        key: ${{ env.cache-name }}-${{ hashFiles('**/CMakeLists.txt', 'cmake/**') }}

    - name: Configure CMake
      run: cmake --fresh -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_INTERPROCEDURAL_OPTIMIZATION_RELEASE=ON -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DENABLE_QT_GUI=ON -DENABLE_UPDATER=ON -DCMAKE_C_COMPILER_LAUNCHER=ccache -DCMAKE_CXX_COMPILER_LAUNCHER=ccache

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} --parallel $(nproc)

    - name: Run AppImage packaging script
      run:  ./.github/linux-appimage-qt.sh

    - name: Package and Upload Linux Qt artifact
      run: |
        tar cf shadps4-linux-qt.tar.gz -C ${{github.workspace}}/build shadps4
    - uses: actions/upload-artifact@v4
      with:
        name: shadps4-linux-qt-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}
        path: Shadps4-qt.AppImage

  pre-release:
    if: github.ref == 'refs/heads/main' && github.repository == 'shadps4-emu/shadPS4' && github.event_name == 'push'
    needs: [get-info, windows-sdl, windows-qt, macos-sdl, macos-qt, linux-sdl, linux-qt]
    runs-on: ubuntu-latest
    steps:
    - name: Download all artifacts
      uses: actions/download-artifact@v4
      with:
        path: ./artifacts
  
    - name: Compress individual directories (without parent directory)
      run: |
        cd ./artifacts
        for dir in */; do
          if [ -d "$dir" ]; then
            dir_name=${dir%/}
            echo "Creating zip for $dir_name"
            (cd "$dir_name" && zip -r "../${dir_name}.zip" .)
          fi
        done
  
    - name: Get latest release information
      id: get_latest_release
      env:
        GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
      run: |
        api_url="https://api.github.com/repos/${{ github.repository }}"
        latest_release_info=$(curl -H "Authorization: token $GITHUB_TOKEN" "$api_url/releases/latest")
        echo "last_release_tag=$(echo "$latest_release_info" | jq -r '.tag_name')" >> $GITHUB_ENV

    - name: Create Pre-Release on GitHub
      id: create_release
      uses: ncipollo/release-action@v1
      with:
        token: ${{ secrets.SHADPS4_TOKEN_REPO }}
        name: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
        tag: "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}"
        draft: false
        prerelease: true
        body: "Full Changelog: [${{ env.last_release_tag }}...${{ needs.get-info.outputs.shorthash }}](https://github.com/shadps4-emu/shadPS4/compare/${{ env.last_release_tag }}...${{ needs.get-info.outputs.fullhash }})"
        artifacts: ./artifacts/*.zip

    - name: Publish to Release Repository
      env:
        GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
      run: |
        ARTIFACTS_DIR=./artifacts
        REPO_WINDOWS="shadps4-emu/shadps4-binaries-Windows"
        REPO_LINUX="shadps4-emu/shadps4-binaries-Linux"
        REPO_MAC="shadps4-emu/shadps4-binaries-Mac"

        for file in "$ARTIFACTS_DIR"/*.zip; do
          filename=$(basename "$file")
          REPO=""

          # Determine repository based on file name
          if [[ "$filename" == *"win64"* ]]; then
            REPO=$REPO_WINDOWS
          elif [[ "$filename" == *"linux"* ]] || [[ "$filename" == *"ubuntu64"* ]]; then
            REPO=$REPO_LINUX
          elif [[ "$filename" == *"macos"* ]]; then
            REPO=$REPO_MAC
          fi

          # If REPO is empty, skip file
          if [[ -z "$REPO" ]]; then
            echo "No matching repository for $filename"
            continue
          fi

          # Check if release already exists and get ID
          release_id=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
            "https://api.github.com/repos/$REPO/releases/tags/Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}" | jq -r '.id')

          if [[ "$release_id" == "null" ]]; then
            echo "Creating release in $REPO for $filename"
            release_id=$(curl -s -X POST -H "Authorization: token $GITHUB_TOKEN" \
              -H "Accept: application/vnd.github.v3+json" \
              -d '{
                "tag_name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}",
                "name": "Pre-release-shadPS4-${{ needs.get-info.outputs.date }}-${{ needs.get-info.outputs.shorthash }}",
                "draft": false,
                "prerelease": true,
                "body": "Commit: [${{ needs.get-info.outputs.fullhash }}](https://github.com/shadps4-emu/shadPS4/commit/${{ needs.get-info.outputs.fullhash }})"
              }' "https://api.github.com/repos/$REPO/releases" | jq -r '.id')
          else
            echo "Release already exists in $REPO with ID $release_id"
          fi

          # Artifact upload
          echo "Uploading $filename to release $release_id in $REPO"
          upload_url="https://uploads.github.com/repos/$REPO/releases/$release_id/assets?name=$filename"
          curl -X POST -H "Authorization: token $GITHUB_TOKEN" -H "Content-Type: application/octet-stream" --data-binary @"$file" "$upload_url"
        done
        
    - name: Get current pre-release information
      env:
        GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
      run: |
        api_url="https://api.github.com/repos/${{ github.repository }}/releases"
        
        # Get all releases (sorted by date)
        releases=$(curl -H "Authorization: token $GITHUB_TOKEN" "$api_url")
        
        # Capture the most recent pre-release (assuming the first one is the latest)
        current_release=$(echo "$releases" | jq -c '.[] | select(.prerelease == true) | .published_at' | sort -r | head -n 1)
        
        # Remove extra quotes from captured date
        current_release=$(echo $current_release | tr -d '"')
                
        # Export the current published_at to be available for the next step
        echo "CURRENT_PUBLISHED_AT=$current_release" >> $GITHUB_ENV
    
    - name: Delete old pre-releases and tags
      env:
        GITHUB_TOKEN: ${{ secrets.SHADPS4_TOKEN_REPO }}
      run: |
        api_url="https://api.github.com/repos/${{ github.repository }}/releases"
        
        # Get current pre-releases
        releases=$(curl -H "Authorization: token $GITHUB_TOKEN" "$api_url")
                
        # Remove extra quotes from captured date
        CURRENT_PUBLISHED_AT=$(echo $CURRENT_PUBLISHED_AT | tr -d '"')
        
        # Convert CURRENT_PUBLISHED_AT para timestamp Unix
        current_published_ts=$(date -d "$CURRENT_PUBLISHED_AT" +%s)
        
        # Identify pre-releases
        echo "$releases" | jq -c '.[] | select(.prerelease == true)' | while read -r release; do
          release_date=$(echo "$release" | jq -r '.published_at')
          release_id=$(echo "$release" | jq -r '.id')
          release_tag=$(echo "$release" | jq -r '.tag_name')
          
          # Remove extra quotes from captured date
          release_date=$(echo $release_date | tr -d '"')
          
          # Convert release_date para timestamp Unix
          release_date_ts=$(date -d "$release_date" +%s)
                    
          # Compare timestamps and delete old pre-releases
          if [[ "$release_date_ts" -lt "$current_published_ts" ]]; then
            echo "Deleting old pre-release: $release_id from $release_date with tag: $release_tag"
            # Delete the pre-release
            curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" "$api_url/$release_id"
            # Delete the tag
            curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" "https://api.github.com/repos/${{ github.repository }}/git/refs/tags/$release_tag"
          else
            echo "Skipping pre-release: $release_id (newer or same date)"
          fi
        done