name: AppImage Build

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

jobs:
  appimage_build:
    runs-on: ubuntu-22.04

    permissions:
      contents: read
      id-token: write
      attestations: write
      artifact-metadata: write

    steps:
      - uses: actions/checkout@v5
        with:
          submodules: true

      - name: Install build dependencies
        run: |
          set -eux
          sudo apt-get update
          sudo apt-get install -y --no-install-recommends \
            build-essential pkg-config meson ninja-build cmake \
            gettext \
            libcanberra-dev libdbus-glib-1-dev libglib2.0-dev \
            libarchive-dev \
            libgtk-3-dev \
            libenchant-2-2 enchant-2 \
            libnuspell5 \
            libwayland-client0 libwayland-cursor0 libwayland-egl1 \
            libxkbcommon0 \
            libgtk-3-bin libglib2.0-bin shared-mime-info gsettings-desktop-schemas \
            libluajit-5.1-dev libpci-dev libperl-dev libssl-dev libayatana-appindicator3-dev \
            perl python3 python3-minimal python3-dev python3-cffi mono-devel desktop-file-utils \
            hunspell hunspell-en-us hunspell-en-gb hunspell-en-ca hunspell-es hunspell-fr hunspell-de-de hunspell-it hunspell-pt-br hunspell-ru hunspell-uk hunspell-nl hunspell-pl \
            fonts-noto-color-emoji breeze-gtk-theme \
            patchelf file curl

      - name: Configure
        run: |
          set -eux
          rm -rf build
          meson setup build \
            --prefix=/usr \
            -Dtext-frontend=true \
            -Dwith-perl=perl \
            -Dwith-python=python3 \
            -Dauto_features=enabled \
            -Dappindicator=enabled

      - name: Build
        run: |
          set -eux
          ninja -C build

      - name: Install to AppDir
        run: |
          set -eux
          rm -rf AppDir
          DESTDIR="${PWD}/AppDir" ninja -C build install

      - name: Bundle scripting runtimes in AppDir
        run: |
          set -eux

          python3_version="$(python3 -c 'import sys; print(f"{sys.version_info.major}.{sys.version_info.minor}")')"

          install -Dm755 "$(command -v python3)" "AppDir/usr/bin/python3"
          if [ -x "/usr/bin/perl" ]; then
            install -Dm755 /usr/bin/perl AppDir/usr/bin/perl
          fi

          install -d AppDir/usr/lib
          cp -a "/usr/lib/python${python3_version}" "AppDir/usr/lib/"

          if [ -d "/usr/lib/python3/dist-packages" ]; then
            install -d AppDir/usr/lib/python3
            cp -a /usr/lib/python3/dist-packages AppDir/usr/lib/python3/
          fi

          if [ -d "/usr/lib/x86_64-linux-gnu/python3/dist-packages" ]; then
            install -d AppDir/usr/lib/x86_64-linux-gnu/python3
            cp -a /usr/lib/x86_64-linux-gnu/python3/dist-packages AppDir/usr/lib/x86_64-linux-gnu/python3/
          fi

          if [ -d "/usr/lib/x86_64-linux-gnu/perl" ]; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/perl AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if [ -d "/usr/share/perl" ]; then
            install -d AppDir/usr/share
            cp -a /usr/share/perl AppDir/usr/share/
          fi

          if [ -d "/usr/share/perl5" ]; then
            install -d AppDir/usr/share
            cp -a /usr/share/perl5 AppDir/usr/share/
          fi
          if compgen -G '/usr/lib/x86_64-linux-gnu/libpython3*.so*' > /dev/null; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/libpython3*.so* AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if [ -d "/usr/share/gtk-3.0/emoji" ]; then
            install -d AppDir/usr/share/gtk-3.0
            cp -a /usr/share/gtk-3.0/emoji AppDir/usr/share/gtk-3.0/
          fi

          if [ -f "/usr/share/fonts/truetype/noto/NotoColorEmoji.ttf" ]; then
            install -d AppDir/usr/share/fonts/truetype/noto
            cp -a /usr/share/fonts/truetype/noto/NotoColorEmoji.ttf AppDir/usr/share/fonts/truetype/noto/
          fi

          if [ -d "/usr/lib/x86_64-linux-gnu/gtk-3.0/modules" ]; then
            install -d AppDir/usr/lib/x86_64-linux-gnu/gtk-3.0
            cp -a /usr/lib/x86_64-linux-gnu/gtk-3.0/modules AppDir/usr/lib/x86_64-linux-gnu/gtk-3.0/
          fi

          if [ -d "/usr/lib/gtk-3.0/modules" ]; then
            install -d AppDir/usr/lib/gtk-3.0
            cp -a /usr/lib/gtk-3.0/modules AppDir/usr/lib/gtk-3.0/
          fi

          if compgen -G '/usr/lib/x86_64-linux-gnu/libenchant-2.so*' > /dev/null; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/libenchant-2.so* AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if compgen -G '/usr/lib/x86_64-linux-gnu/libgmodule-2.0.so*' > /dev/null; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/libgmodule-2.0.so* AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if compgen -G '/usr/lib/x86_64-linux-gnu/libnuspell.so*' > /dev/null; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/libnuspell.so* AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if compgen -G '/usr/lib/x86_64-linux-gnu/libhunspell-*.so*' > /dev/null; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/libhunspell-*.so* AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if [ -d "/usr/lib/x86_64-linux-gnu/enchant-2" ]; then
            install -d AppDir/usr/lib/x86_64-linux-gnu
            cp -a /usr/lib/x86_64-linux-gnu/enchant-2 AppDir/usr/lib/x86_64-linux-gnu/
          fi

          if [ -d "/usr/share/enchant-2" ]; then
            install -d AppDir/usr/share
            cp -a /usr/share/enchant-2 AppDir/usr/share/
          fi

          if [ -d "/etc/enchant-2" ]; then
            install -d AppDir/etc
            cp -a /etc/enchant-2 AppDir/etc/
          fi

          if [ -d "/usr/share/hunspell" ]; then
            install -d AppDir/usr/share
            cp -a /usr/share/hunspell AppDir/usr/share/
          fi

      - name: Verify bundled plugins
        run: |
          set -eux

          find AppDir/usr/lib -maxdepth 4 -type f -name '*.so' -path '*/zoitechat/plugins/*' -print | sort

          for plugin in checksum fishlim lua perl python sysinfo; do
            find "AppDir/usr/lib" -maxdepth 4 -type f -name "${plugin}.so" -path '*/zoitechat/plugins/*' -print -quit | grep -q .
          done

          find AppDir/usr/lib/x86_64-linux-gnu -maxdepth 1 \( -type f -o -type l \) -name 'libenchant-2.so*' -print -quit | grep -q .
          find AppDir/usr/lib/x86_64-linux-gnu -maxdepth 1 \( -type f -o -type l \) -name 'libgmodule-2.0.so*' -print -quit | grep -q .
          find AppDir/usr/lib/x86_64-linux-gnu -maxdepth 1 -type f -name 'libhunspell-*.so*' -print -quit | grep -q .
          find AppDir/usr/lib/x86_64-linux-gnu/enchant-2 -maxdepth 1 -type f -name '*hunspell*.so*' -print -quit | grep -q .
          test -f AppDir/usr/share/hunspell/en_CA.dic
          test -f AppDir/usr/share/hunspell/en_CA.aff
          test -d AppDir/usr/share/enchant-2
          ldd -r AppDir/usr/lib/x86_64-linux-gnu/libenchant-2.so.2 | tee /tmp/ldd-enchant.txt
          if grep -q 'undefined symbol' /tmp/ldd-enchant.txt; then
            exit 1
          fi

      - name: Build AppImage
        env:
          APPIMAGE_EXTRACT_AND_RUN: 1
          DEPLOY_GTK_VERSION: 3
          LDAI_NO_APPSTREAM: 1
        run: |
          set -eux

          curl -fL --retry 3 -o linuxdeploy-x86_64.AppImage \
            https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-x86_64.AppImage
          chmod +x linuxdeploy-x86_64.AppImage

          curl -fL --retry 3 -o linuxdeploy-plugin-gtk \
            https://raw.githubusercontent.com/linuxdeploy/linuxdeploy-plugin-gtk/master/linuxdeploy-plugin-gtk.sh
          chmod +x linuxdeploy-plugin-gtk
          export PATH="${PWD}:${PATH}"

          install -Dm644 /etc/ssl/certs/ca-certificates.crt \
            AppDir/etc/ssl/certs/ca-certificates.crt

          cat > AppRun <<'EOF'
          #!/bin/sh
          set -eu

          APPDIR="${APPDIR:-$(dirname "$(readlink -f "$0")")}"

          export PATH="${PATH:-/usr/bin:/bin}:$APPDIR/usr/bin"
          export LD_LIBRARY_PATH="$APPDIR/usr/lib:$APPDIR/usr/lib/x86_64-linux-gnu:${LD_LIBRARY_PATH:-}"
          export XDG_DATA_DIRS="$APPDIR/usr/share:${XDG_DATA_DIRS:-/usr/local/share:/usr/share}"
          export GTK_EXE_PREFIX="$APPDIR/usr"
          export GTK_DATA_PREFIX="$APPDIR/usr"
          export ENCHANT_PREFIX="$APPDIR/usr"
          export DICPATH="$APPDIR/usr/share/hunspell${DICPATH:+:$DICPATH}"
          export ENCHANT_CONFIG_DIR="$APPDIR/etc/enchant-2"
          gtk_path_entries=""
          if [ -d "$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0" ]; then
            gtk_path_entries="$APPDIR/usr/lib/x86_64-linux-gnu/gtk-3.0"
          fi
          if [ -d "$APPDIR/usr/lib/gtk-3.0" ]; then
            gtk_path_entries="${gtk_path_entries:+$gtk_path_entries:}$APPDIR/usr/lib/gtk-3.0"
          fi
          if [ -n "$gtk_path_entries" ]; then
            export GTK_PATH="$gtk_path_entries${GTK_PATH:+:$GTK_PATH}"
          fi

          if [ -d "$APPDIR/etc/fonts" ]; then
            export FONTCONFIG_SYSROOT="$APPDIR"
            export FONTCONFIG_PATH="$APPDIR/etc/fonts${FONTCONFIG_PATH:+:$FONTCONFIG_PATH}"
            if [ -f "$APPDIR/etc/fonts/fonts.conf" ]; then
              export FONTCONFIG_FILE="$APPDIR/etc/fonts/fonts.conf"
            fi
          fi

          if [ -d "$APPDIR/usr/lib/x86_64-linux-gnu/zoitechat/plugins" ]; then
            export ZOITECHAT_LIBDIR="$APPDIR/usr/lib/x86_64-linux-gnu/zoitechat/plugins"
          elif [ -d "$APPDIR/usr/lib/zoitechat/plugins" ]; then
            export ZOITECHAT_LIBDIR="$APPDIR/usr/lib/zoitechat/plugins"
          fi

          if [ -d "$APPDIR/usr/share/glib-2.0/schemas" ]; then
            export GSETTINGS_SCHEMA_DIR="$APPDIR/usr/share/glib-2.0/schemas${GSETTINGS_SCHEMA_DIR:+:$GSETTINGS_SCHEMA_DIR}"
          fi

          if [ -d "$APPDIR/usr/lib/x86_64-linux-gnu/gio/modules" ]; then
            gio_module_dir="$APPDIR/usr/lib/x86_64-linux-gnu/gio/modules"
          elif [ -d "$APPDIR/usr/lib/gio/modules" ]; then
            gio_module_dir="$APPDIR/usr/lib/gio/modules"
          else
            gio_module_dir=""
          fi

          if [ -n "$gio_module_dir" ]; then
            export GIO_MODULE_DIR="$gio_module_dir"
            export GIO_EXTRA_MODULES="$gio_module_dir"
          fi

          unset GTK_MODULES

          export PYTHONHOME="$APPDIR/usr"
          python_stdlib_dir="$(find "$APPDIR/usr/lib" -maxdepth 1 -type d -name 'python3.*' | head -n 1 || true)"
          pythonpath_entries=""
          if [ -n "$python_stdlib_dir" ] && [ -d "$python_stdlib_dir/dist-packages" ]; then
            pythonpath_entries="$python_stdlib_dir/dist-packages"
          fi
          if [ -d "$APPDIR/usr/lib/python3/dist-packages" ]; then
            pythonpath_entries="${pythonpath_entries:+$pythonpath_entries:}$APPDIR/usr/lib/python3/dist-packages"
          fi
          if [ -d "$APPDIR/usr/lib/x86_64-linux-gnu/python3/dist-packages" ]; then
            pythonpath_entries="${pythonpath_entries:+$pythonpath_entries:}$APPDIR/usr/lib/x86_64-linux-gnu/python3/dist-packages"
          fi
          if [ -n "$pythonpath_entries" ]; then
            export PYTHONPATH="$pythonpath_entries${PYTHONPATH:+:$PYTHONPATH}"
          fi

          # OpenSSL trust store override
          export SSL_CERT_FILE="${SSL_CERT_FILE:-$APPDIR/etc/ssl/certs/ca-certificates.crt}"
          export SSL_CERT_DIR="${SSL_CERT_DIR:-$APPDIR/etc/ssl/certs}"
          export CURL_CA_BUNDLE="${CURL_CA_BUNDLE:-$SSL_CERT_FILE}"

          # Prefer Wayland if the session provides it, but keep X11 fallback.
          # Don't override if the user already set GDK_BACKEND explicitly.
          if [ -z "${GDK_BACKEND:-}" ]; then
            if [ -n "${WAYLAND_DISPLAY:-}" ] || [ "${XDG_SESSION_TYPE:-}" = "wayland" ]; then
              export GDK_BACKEND="wayland,x11"
            else
              export GDK_BACKEND="x11"
            fi
          fi

          for hook_dir in "$APPDIR/apprun-hooks" "$APPDIR/usr/apprun-hooks"; do
            if [ -d "$hook_dir" ]; then
              for hook in "$hook_dir"/*.sh; do
                if [ -f "$hook" ]; then
                  . "$hook"
                fi
              done
            fi
          done

          exec "$APPDIR/usr/bin/zoitechat" "$@"
          EOF
          chmod +x AppRun


          VERSION="$(git describe --tags --always)"

          ./linuxdeploy-x86_64.AppImage \
            --appdir AppDir \
            --desktop-file AppDir/usr/share/applications/net.zoite.Zoitechat.desktop \
            --icon-file AppDir/usr/share/icons/hicolor/48x48/apps/net.zoite.Zoitechat.png \
            --custom-apprun ./AppRun \
            --plugin gtk \
            --output appimage

          appimage_path="$(ls -1 *.AppImage | grep -v linuxdeploy | head -n 1)"
          mv "$appimage_path" "Zoitechat-${VERSION}-x86_64.AppImage"

      - name: Attest AppImage (Build Provenance)
        if: ${{ github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository }}
        uses: actions/attest-build-provenance@v3
        with:
          subject-path: Zoitechat-*-x86_64.AppImage

      - name: Upload AppImage artifact
        uses: actions/upload-artifact@v6
        with:
          name: zoitechat-appimage
          path: Zoitechat-*-x86_64.AppImage
