name: Build AppImage

on:
  push:
    tags:
      - 'v*'
  workflow_dispatch:

# APPIMAGE_EXTRACT_AND_RUN=1 is required because GitHub Actions runners
# do not have FUSE available, which AppImage tools need to self-mount.
env:
  APPIMAGE_EXTRACT_AND_RUN: "1"

jobs:
  appimage:
    runs-on: ubuntu-22.04

    steps:
      - uses: actions/checkout@v4

      # Install Qt 6.7 via the official Qt online installer.
      # jurplel/install-qt-action sets QT_ROOT_DIR in the environment,
      # which we later pass to linuxdeploy-plugin-qt via QMAKE.
      - name: Install Qt 6
        uses: jurplel/install-qt-action@v4
        with:
          version: '6.7.*'
          host: 'linux'
          target: 'desktop'
          arch: 'linux_gcc_64'

      - name: Install build dependencies
        run: |
          sudo apt-get update
          sudo apt-get install -y libgraphicsmagick++-dev libomp-dev \
            libfftw3-dev libcurl4-openssl-dev

      # Build the application and stage it into appdir/ using the
      # standard qmake INSTALL_ROOT mechanism. The .pro already has
      # correct INSTALLS targets for binary, icons, .desktop, and appstream.
      - name: Build and stage
        run: |
          qmake CONFIG+=release PREFIX=/usr
          make -j$(nproc)
          make install INSTALL_ROOT=$PWD/appdir

      # AppImages are relocatable and don't inherit the host's XDG_DATA_DIRS,
      # so MainWindow::loadTranslator() can't find the .qm files installed
      # under usr/share/photoflare/languages/ (that lookup only works for
      # .deb installs because /usr/share happens to be a host XDG_DATA_DIR).
      # Mirror the .qm files next to the binary so the applicationDirPath()
      # lookup in loadTranslator() finds them.
      - name: Stage translations next to binary
        run: |
          mkdir -p appdir/usr/bin/languages
          cp appdir/usr/share/photoflare/languages/*.qm appdir/usr/bin/languages/

      # Clone gmic-qt and the matching G'MIC source tree, build the standalone
      # gmic_qt binary, and stage it into appdir/usr/bin/ alongside photoflare.
      - name: Build and stage gmic-qt
        run: |
          git clone --depth 1 --branch v.3.4.2 https://github.com/c-koi/gmic-qt.git gmic-qt-src
          # Pin GMIC core to v.3.7.6: it's the last release where gmic::init_rc()
          # still returns bool. gmic-qt v.3.4.2 (last tagged gmic-qt release, and
          # its current master branch too) calls it as `create && gmic::init_rc()`,
          # which fails to compile against gmic >= v.4.0.0, where init_rc() was
          # changed to return void. Bumping GMIC core past v.4.0.0 (as previously
          # tried) breaks this API compatibility, even though it fixes the stdlib
          # header 404 below.
          git clone --depth 1 --branch v.3.7.6 https://github.com/GreycLab/gmic.git gmic-qt-src/gmic
          GMIC_SRC="$PWD/gmic-qt-src/gmic/src"
          GMIC_VER=$(grep -oP '(?<=gmic_version )\d+' "$GMIC_SRC/gmic.h")
          CIMG_TAG="v.${GMIC_VER:0:1}.${GMIC_VER:1:1}.${GMIC_VER:2:1}"
          wget --no-check-certificate --quiet -O "$GMIC_SRC/CImg.h" \
            "https://github.com/GreycLab/CImg/raw/${CIMG_TAG}/CImg.h"
          # gmic.eu only hosts gmic_stdlib_community<VERSION>.h for whatever the
          # CURRENT GMIC release is (older pinned versions 404 there), but the
          # header's compressed G'MIC-script content isn't version-locked at
          # compile time -- it's just a `data_gmic`/`size_data_gmic` byte array,
          # and CMake's GMIC_PATH build only checks gmic.h vs CImg.h consistency,
          # not the stdlib header's version. So resolve whatever the latest GMIC
          # release actually is and fetch that header, decoupled from the core
          # version pinned above for API compatibility.
          LATEST_GMIC_TAG=$(curl -fsSL https://api.github.com/repos/GreycLab/gmic/releases/latest \
            | grep -oP '"tag_name":\s*"\K[^"]+') \
            || { echo "Failed to resolve latest GMIC release tag"; exit 1; }
          LATEST_GMIC_VER="${LATEST_GMIC_TAG#v.}"
          LATEST_GMIC_VER="${LATEST_GMIC_VER//./}"
          wget --quiet -O "$GMIC_SRC/gmic_stdlib_community.h" \
            "https://gmic.eu/gmic_stdlib_community${LATEST_GMIC_VER}.h" \
            || { echo "Failed to download gmic_stdlib_community.h"; exit 1; }
          # Sanity check: this header must define the data_gmic/size_data_gmic
          # symbols that gmic.cpp's decompress_stdlib() expects, otherwise fail
          # fast here instead of with a confusing compile error later.
          if ! grep -q 'data_gmic' "$GMIC_SRC/gmic_stdlib_community.h"; then
            echo "gmic_stdlib_community.h does not define data_gmic; aborting"
            exit 1
          fi
          cmake gmic-qt-src -B build-gmic-qt \
            -DCMAKE_PREFIX_PATH="${QT_ROOT_DIR}" \
            -DBUILD_WITH_QT6=ON \
            -DGMIC_QT_HOST=none \
            -DENABLE_SYSTEM_GMIC=OFF \
            -DGMIC_PATH="$PWD/gmic-qt-src/gmic/src" \
            -DENABLE_FFTW3=ON \
            -DENABLE_CURL=ON \
            -DCMAKE_BUILD_TYPE=Release \
            -DCMAKE_EXE_LINKER_FLAGS="-no-pie"
          cmake --build build-gmic-qt --parallel
          cp build-gmic-qt/gmic_qt appdir/usr/bin/gmic_photoflare_qt

      # Download linuxdeploy and its Qt plugin into a tools/ subdirectory
      # so they do not match the *.AppImage upload glob later.
      - name: Download linuxdeploy
        run: |
          mkdir tools
          wget -nv -P tools \
            https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage \
            https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-x86_64.AppImage
          chmod +x tools/*.AppImage

      # linuxdeploy-plugin-qt needs QMAKE to point at the correct Qt 6 qmake
      # so it can discover Qt plugins and translations.
      # VERSION is used by linuxdeploy to name the output file.
      - name: Build AppImage
        env:
          QMAKE: ${{ env.QT_ROOT_DIR }}/bin/qmake
          VERSION: ${{ github.ref_name }}
        run: |
          export PATH="$PWD/tools:$PATH"
          ./tools/linuxdeploy-x86_64.AppImage \
            --appdir appdir \
            --plugin qt \
            --output appimage

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: photoflare-appimage
          path: '*.AppImage'
          if-no-files-found: error

      # Attach the AppImage to the GitHub Release when triggered by a tag push.
      - name: Upload to release
        if: startsWith(github.ref, 'refs/tags/')
        uses: softprops/action-gh-release@v2
        with:
          files: '*.AppImage'
