name: Build sideloaded IPA from Release Assets

on:
    workflow_dispatch:
        inputs:
            build_sideload:
                description: "Build normal sideload IPA (zxPluginsInject + ipapatch)"
                default: true
                required: false
                type: boolean
            build_noplugins:
                description: "Build no-plugins IPA (NoPluginsPatch, any sideloader)"
                default: false
                required: false
                type: boolean
            decrypted_instagram_url:
                description: "Direct URL to the decrypted Instagram IPA"
                default: ""
                required: true
                type: string
            release_tag:
                description: "Release tag to pull assets from (leave empty for latest, e.g. v1.3.0)"
                default: ""
                required: false
                type: string
            upload_artifact:
                description: "Upload artifact"
                default: true
                required: false
                type: boolean

concurrency:
    group: ${{ github.workflow }}-${{ github.ref }}
    cancel-in-progress: true

env:
    UPSTREAM_REPO: faroukbmiled/RyukGram

jobs:
    build:
        name: Build RyukGram from Release
        runs-on: macos-latest
        permissions:
            contents: read

        steps:
            - name: Validate selection
              run: |
                if [ "${{ inputs.build_sideload }}" != "true" ] && \
                   [ "${{ inputs.build_noplugins }}" != "true" ]; then
                  echo "::error::Select at least one of build_sideload / build_noplugins."
                  exit 1
                fi

            - name: Checkout
              uses: actions/checkout@v4

            - name: Install Dependencies
              run: brew install dpkg

            - name: Install IPA tooling (cyan + ipapatch)
              run: |
                pip install --force-reinstall https://github.com/asdfzxcvbn/pyzule-rw/archive/main.zip
                mkdir -p "$HOME/.local/bin"
                curl -fLo "$HOME/.local/bin/ipapatch" https://github.com/asdfzxcvbn/ipapatch/releases/download/v2.1.3/ipapatch.macos-arm64
                chmod +x "$HOME/.local/bin/ipapatch"
                echo "$HOME/.local/bin" >> "$GITHUB_PATH"

            - name: Resolve release tag
              id: tag
              env:
                GH_TOKEN: ${{ github.token }}
                INPUT_TAG: ${{ inputs.release_tag }}
              run: |
                set -euo pipefail
                if [ -n "$INPUT_TAG" ]; then
                  TAG="$INPUT_TAG"
                else
                  TAG="$(gh release view --repo "$UPSTREAM_REPO" --json tagName -q .tagName)"
                fi
                [ -n "$TAG" ] || { echo "::error::Could not resolve release tag."; exit 1; }
                VERSION="${TAG#v}"
                echo "tag=${TAG}" >> "$GITHUB_OUTPUT"
                echo "version=${VERSION}" >> "$GITHUB_OUTPUT"
                echo "TAG=${TAG}" >> "$GITHUB_ENV"
                echo "VERSION=${VERSION}" >> "$GITHUB_ENV"
                echo "Using release tag: ${TAG} (version ${VERSION})"

            - name: Download release assets (rootless deb + injection dylibs)
              env:
                GH_TOKEN: ${{ github.token }}
              run: |
                set -euo pipefail
                mkdir -p packages release-assets

                gh release download "$TAG" --repo "$UPSTREAM_REPO" --dir release-assets \
                  --pattern "RyukGram_*_rootless.deb"
                DEB="$(ls -t release-assets/RyukGram_*_rootless.deb 2>/dev/null | head -n1 || true)"
                [ -n "$DEB" ] || { echo "::error::Rootless .deb not found in release $TAG."; exit 1; }
                echo "DEB=${DEB}" >> "$GITHUB_ENV"

                if [ "${{ inputs.build_sideload }}" = "true" ]; then
                  gh release download "$TAG" --repo "$UPSTREAM_REPO" --dir release-assets \
                    --pattern "zxPluginsInject_v*.dylib"
                  ZX_DYLIB="$(ls -t release-assets/zxPluginsInject_v*.dylib 2>/dev/null | head -n1 || true)"
                  [ -n "$ZX_DYLIB" ] || { echo "::error::zxPluginsInject dylib not found in release $TAG (enable include_zxinject when releasing)."; exit 1; }
                  echo "ZX_DYLIB=${ZX_DYLIB}" >> "$GITHUB_ENV"
                fi

                if [ "${{ inputs.build_noplugins }}" = "true" ]; then
                  gh release download "$TAG" --repo "$UPSTREAM_REPO" --dir release-assets \
                    --pattern "NoPluginsPatch_v*.dylib"
                  NP_DYLIB="$(ls -t release-assets/NoPluginsPatch_v*.dylib 2>/dev/null | head -n1 || true)"
                  [ -n "$NP_DYLIB" ] || { echo "::error::NoPluginsPatch dylib not found in release $TAG (enable include_noplugins_patch when releasing)."; exit 1; }
                  echo "NP_DYLIB=${NP_DYLIB}" >> "$GITHUB_ENV"
                fi

                ls -la release-assets

            - name: Extract dylib + bundle from rootless deb
              run: |
                set -euo pipefail
                STAGE="$(mktemp -d)"
                dpkg-deb -x "$DEB" "$STAGE"

                DYLIB_SRC="$(find "$STAGE" -type f -name 'RyukGram.dylib' | head -1)"
                BUNDLE_SRC="$(find "$STAGE" -type d -name 'RyukGram.bundle' | head -1)"
                [ -n "$DYLIB_SRC" ] || { echo "::error::RyukGram.dylib not found in deb."; exit 1; }
                [ -n "$BUNDLE_SRC" ] || { echo "::error::RyukGram.bundle not found in deb."; exit 1; }

                cp "$DYLIB_SRC" packages/RyukGram.dylib
                rm -rf packages/RyukGram.bundle
                cp -R "$BUNDLE_SRC" packages/RyukGram.bundle

                if [ "${{ inputs.build_sideload }}" = "true" ]; then
                  # Match the @rpath LC that ipapatch writes into target binaries.
                  cp "$ZX_DYLIB" packages/zxPluginsInject.dylib
                  install_name_tool -id "@rpath/zxPluginsInject.dylib" packages/zxPluginsInject.dylib 2>/dev/null || true
                fi

                if [ "${{ inputs.build_noplugins }}" = "true" ]; then
                  cp "$NP_DYLIB" packages/NoPluginsPatch.dylib
                fi

                rm -rf "$STAGE"
                ls -la packages
                ls -la packages/RyukGram.bundle | head -20

            - name: Prepare Instagram IPA
              env:
                Instagram_URL: ${{ inputs.decrypted_instagram_url }}
              run: |
                set -euo pipefail
                wget "$Instagram_URL" --no-verbose -O packages/com.burbn.instagram.ipa
                ls -la packages

            - name: Build sideloaded IPA (cyan + ipapatch with zxPluginsInject)
              if: ${{ inputs.build_sideload }}
              run: |
                set -euo pipefail
                rm -f packages/RyukGram-sideloaded.ipa
                cyan \
                  -i packages/com.burbn.instagram.ipa \
                  -o packages/RyukGram-sideloaded.ipa \
                  -f packages/RyukGram.dylib packages/RyukGram.bundle \
                  -c 9 -m 15.0 -du

                # Embed Safari "Open in Instagram" extension before ipapatch
                # re-signs, so instagram.com links open the app.
                APPEX_SRC="extensions/OpenInstagramSafariExtension.appex"
                if [ -d "$APPEX_SRC" ]; then
                  echo "Embedding Safari extension"
                  INJECT_TMP="$(mktemp -d)"
                  unzip -q packages/RyukGram-sideloaded.ipa -d "$INJECT_TMP"
                  APP_DIR="$(find "$INJECT_TMP/Payload" -maxdepth 1 -type d -name '*.app' | head -1)"
                  if [ -n "$APP_DIR" ]; then
                    mkdir -p "$APP_DIR/PlugIns"
                    rm -rf "$APP_DIR/PlugIns/OpenInstagramSafariExtension.appex"
                    cp -R "$APPEX_SRC" "$APP_DIR/PlugIns/"
                    ( cd "$INJECT_TMP" && zip -qr -9 ../repacked.ipa Payload )
                    mv "$INJECT_TMP/../repacked.ipa" packages/RyukGram-sideloaded.ipa
                  fi
                  rm -rf "$INJECT_TMP"
                fi

                echo "Running ipapatch (zxPluginsInject LC injection)"
                ipapatch \
                  --input packages/RyukGram-sideloaded.ipa \
                  --inplace --noconfirm \
                  --dylib packages/zxPluginsInject.dylib

                mv packages/RyukGram-sideloaded.ipa "packages/RyukGram_sideloaded_v${VERSION}.ipa"
                ls -la packages

            - name: Build no-plugins IPA (cyan + NoPluginsPatch, appex stripped)
              if: ${{ inputs.build_noplugins }}
              run: |
                set -euo pipefail
                rm -f packages/RyukGram-noplugins.ipa
                cyan \
                  -i packages/com.burbn.instagram.ipa \
                  -o packages/RyukGram-noplugins.ipa \
                  -f packages/RyukGram.dylib packages/NoPluginsPatch.dylib packages/RyukGram.bundle \
                  -c 9 -m 15.0 -du

                # No-plugins: strip every app extension (no ipapatch, no Safari ext).
                INJECT_TMP="$(mktemp -d)"
                unzip -q packages/RyukGram-noplugins.ipa -d "$INJECT_TMP"
                APP_DIR="$(find "$INJECT_TMP/Payload" -maxdepth 1 -type d -name '*.app' | head -1)"
                if [ -n "$APP_DIR" ]; then
                  find "$APP_DIR" -type d -name '*.appex' -prune -exec rm -rf {} +
                  ( cd "$INJECT_TMP" && zip -qr -9 ../repacked.ipa Payload )
                  mv "$INJECT_TMP/../repacked.ipa" packages/RyukGram-noplugins.ipa
                fi
                rm -rf "$INJECT_TMP"

                mv packages/RyukGram-noplugins.ipa "packages/RyukGram_noplugins_v${VERSION}.ipa"
                ls -la packages

            - name: Upload sideload IPA artifact
              if: ${{ inputs.upload_artifact && inputs.build_sideload }}
              uses: actions/upload-artifact@v4
              with:
                name: RyukGram_sideloaded_v${{ steps.tag.outputs.version }}
                path: packages/RyukGram_sideloaded_v*.ipa
                if-no-files-found: error

            - name: Upload no-plugins IPA artifact
              if: ${{ inputs.upload_artifact && inputs.build_noplugins }}
              uses: actions/upload-artifact@v4
              with:
                name: RyukGram_noplugins_v${{ steps.tag.outputs.version }}
                path: packages/RyukGram_noplugins_v*.ipa
                if-no-files-found: error
