name: 🏗️ Build Apps

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

on:
  workflow_dispatch:
  pull_request:
    branches: [develop, master]
  push:
    branches: [develop, master]

jobs:
  build-android-phone:
    if: (!contains(github.event.head_commit.message, '[skip ci]'))
    runs-on: ubuntu-24.04
    name: 🤖 Build Android APK (Phone)
    permissions:
      contents: read

    steps:
      - name: 🗑️ Free Disk Space
        uses: BRAINSia/free-disk-space@7048ffbf50819342ac964ef3998a51c2564a8a75 # v2.1.3
        with:
          tool-cache: false
          mandb: true
          android: false
          dotnet: true
          haskell: true
          large-packages: true
          docker-images: true
          swap-storage: false

      - name: 📥 Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          fetch-depth: 0
          submodules: recursive
          show-progress: false

      - name: 🍞 Setup Bun
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
        with:
          bun-version: latest

      - name: 💾 Cache Bun dependencies
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.bun/install/cache
          key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }}
          restore-keys: |
            ${{ runner.os }}-${{ runner.arch }}-bun-develop
            ${{ runner.os }}-bun-develop

      - name: 📦 Install dependencies and reload submodules
        run: |
          bun install --frozen-lockfile
          bun run submodule-reload

      - name: 💾 Cache Gradle global
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: 🛠️ Generate project files
        run: bun run prebuild

      - name: 💾 Cache project Gradle (.gradle)
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: android/.gradle
          key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
          restore-keys: ${{ runner.os }}-android-gradle-develop

      - name: 🚀 Build APK
        env:
          EXPO_TV: 0
        run: bun run build:android:local

      - name: 📅 Set date tag
        run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV

      - name: 📤 Upload APK artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: streamyfin-android-phone-apk-${{ env.DATE_TAG }}
          path: |
            android/app/build/outputs/apk/release/*.apk
          retention-days: 7

  build-android-tv:
    if: (!contains(github.event.head_commit.message, '[skip ci]'))
    runs-on: ubuntu-24.04
    name: 🤖 Build Android APK (TV)
    permissions:
      contents: read

    steps:
      - name: 🗑️ Free Disk Space
        uses: BRAINSia/free-disk-space@7048ffbf50819342ac964ef3998a51c2564a8a75 # v2.1.3
        with:
          tool-cache: false
          mandb: true
          android: false
          dotnet: true
          haskell: true
          large-packages: true
          docker-images: true
          swap-storage: false

      - name: 📥 Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          fetch-depth: 0
          submodules: recursive
          show-progress: false

      - name: 🍞 Setup Bun
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
        with:
          bun-version: latest

      - name: 💾 Cache Bun dependencies
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.bun/install/cache
          key: ${{ runner.os }}-${{ runner.arch }}-bun-develop-${{ hashFiles('bun.lock') }}
          restore-keys: |
            ${{ runner.os }}-${{ runner.arch }}-bun-develop
            ${{ runner.os }}-bun-develop

      - name: 📦 Install dependencies and reload submodules
        run: |
          bun install --frozen-lockfile
          bun run submodule-reload

      - name: 💾 Cache Gradle global
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: |
            ~/.gradle/caches
            ~/.gradle/wrapper
          key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
          restore-keys: |
            ${{ runner.os }}-gradle-

      - name: 🛠️ Generate project files
        run: bun run prebuild:tv

      - name: 💾 Cache project Gradle (.gradle)
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: android/.gradle
          key: ${{ runner.os }}-android-gradle-develop-${{ hashFiles('android/**/build.gradle', 'android/gradle/wrapper/gradle-wrapper.properties') }}
          restore-keys: ${{ runner.os }}-android-gradle-develop

      - name: 🚀 Build APK
        env:
          EXPO_TV: 1
        run: bun run build:android:local

      - name: 📅 Set date tag
        run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV

      - name: 📤 Upload APK artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: streamyfin-android-tv-apk-${{ env.DATE_TAG }}
          path: |
            android/app/build/outputs/apk/release/*.apk
          retention-days: 7

  build-ios-phone:
    if: (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin'))
    runs-on: macos-26
    name: 🍎 Build iOS IPA (Phone)
    permissions:
      contents: read

    steps:
      - name: 📥 Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          fetch-depth: 0
          submodules: recursive
          show-progress: false

      - name: 🍞 Setup Bun
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
        with:
          bun-version: latest

      - name: 💾 Cache Bun dependencies
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.bun/install/cache
          key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
          restore-keys: |
            ${{ runner.os }}-bun-cache

      - name: 📦 Install dependencies and reload submodules
        run: |
          bun install --frozen-lockfile
          bun run submodule-reload

      - name: 🛠️ Generate project files
        run: bun run prebuild

      - name: 🔧 Setup Xcode
        uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1
        with:
          # renovate: datasource=custom.xcode depName=xcode versioning=loose
          xcode-version: "26.4"

      - name: 🏗️ Setup EAS
        uses: expo/expo-github-action@b184ff86a3c926240f1b6db41764c83a01c02eef # main
        with:
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}
          eas-cache: true

      - name: 🚀 Build iOS app
        env:
          EXPO_TV: 0
        run: eas build -p ios --local --non-interactive

      - name: 📅 Set date tag
        run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV

      - name: 📤 Upload IPA artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: streamyfin-ios-phone-ipa-${{ env.DATE_TAG }}
          path: build-*.ipa
          retention-days: 7

  build-ios-phone-unsigned:
    if: (!contains(github.event.head_commit.message, '[skip ci]'))
    runs-on: macos-26
    name: 🍎 Build iOS IPA (Phone - Unsigned)
    permissions:
      contents: read

    steps:
      - name: 📥 Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          fetch-depth: 0
          submodules: recursive
          show-progress: false

      - name: 🍞 Setup Bun
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
        with:
          bun-version: latest

      - name: 💾 Cache Bun dependencies
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.bun/install/cache
          key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
          restore-keys: |
            ${{ runner.os }}-bun-cache

      - name: 📦 Install dependencies and reload submodules
        run: |
          bun install --frozen-lockfile
          bun run submodule-reload

      - name: 🛠️ Generate project files
        run: bun run prebuild

      - name: 🔧 Setup Xcode
        uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1
        with:
          # renovate: datasource=custom.xcode depName=xcode versioning=loose
          xcode-version: "26.4"

      - name: 🚀 Build iOS app
        env:
          EXPO_TV: 0
        run: bun run ios:unsigned-build ${{ github.event_name == 'pull_request' && '-- --verbose' || '' }}

      - name: 📅 Set date tag
        run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV

      - name: 📤 Upload IPA artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: streamyfin-ios-phone-unsigned-ipa-${{ env.DATE_TAG }}
          path: build/*.ipa
          retention-days: 7

  build-ios-tv:
    # Temporarily disabled until feat/tv-interface is merged (TV UI not ready).
    # Re-enable by removing the `false &&` prefix below.
    if: false && (!contains(github.event.head_commit.message, '[skip ci]') && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == 'streamyfin/streamyfin'))
    runs-on: macos-26
    name: 🍎 Build tvOS IPA
    permissions:
      contents: read

    steps:
      - name: 📥 Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          fetch-depth: 0
          submodules: recursive
          show-progress: false

      - name: 🍞 Setup Bun
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
        with:
          bun-version: latest

      - name: 💾 Cache Bun dependencies
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.bun/install/cache
          key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
          restore-keys: |
            ${{ runner.os }}-bun-cache

      - name: 📦 Install dependencies and reload submodules
        run: |
          bun install --frozen-lockfile
          bun run submodule-reload

      - name: 🛠️ Generate project files
        run: bun run prebuild:tv

      - name: 🔧 Setup Xcode
        uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1
        with:
          # renovate: datasource=custom.xcode depName=xcode versioning=loose
          xcode-version: "26.4"

      - name: 🏗️ Setup EAS
        uses: expo/expo-github-action@b184ff86a3c926240f1b6db41764c83a01c02eef # main
        with:
          eas-version: latest
          token: ${{ secrets.EXPO_TOKEN }}
          eas-cache: true

      - name: 🚀 Build iOS app
        env:
          EXPO_TV: 1
        run: eas build -p ios --local --non-interactive

      - name: 📅 Set date tag
        run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV

      - name: 📤 Upload IPA artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: streamyfin-ios-tv-ipa-${{ env.DATE_TAG }}
          path: build-*.ipa
          retention-days: 7

  build-ios-tv-unsigned:
    # Unsigned tvOS build is enabled (compiles without Apple credentials).
    # The signed tvOS job above stays disabled until tvOS provisioning
    # profiles are set up in EAS (app + TopShelf targets).
    if: (!contains(github.event.head_commit.message, '[skip ci]'))
    runs-on: macos-26
    name: 🍎 Build tvOS IPA (Unsigned)
    permissions:
      contents: read

    steps:
      - name: 📥 Checkout code
        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
        with:
          ref: ${{ github.event.pull_request.head.sha || github.sha }}
          fetch-depth: 0
          submodules: recursive
          show-progress: false

      - name: 🍞 Setup Bun
        uses: oven-sh/setup-bun@0c5077e51419868618aeaa5fe8019c62421857d6 # v2.2.0
        with:
          bun-version: latest

      - name: 💾 Cache Bun dependencies
        uses: actions/cache@27d5ce7f107fe9357f9df03efb73ab90386fccae # v5.0.5
        with:
          path: ~/.bun/install/cache
          key: ${{ runner.os }}-bun-cache-${{ hashFiles('bun.lock') }}
          restore-keys: |
            ${{ runner.os }}-bun-cache

      - name: 📦 Install dependencies and reload submodules
        run: |
          bun install --frozen-lockfile
          bun run submodule-reload

      - name: 🛠️ Generate project files
        run: bun run prebuild:tv

      - name: 🔧 Setup Xcode
        uses: maxim-lobanov/setup-xcode@ed7a3b1fda3918c0306d1b724322adc0b8cc0a90 # v1
        with:
          # renovate: datasource=custom.xcode depName=xcode versioning=loose
          xcode-version: "26.4"

      - name: 🚀 Build iOS app
        env:
          EXPO_TV: 1
        run: bun run ios:unsigned-build:tv ${{ github.event_name == 'pull_request' && '-- --verbose' || '' }}

      - name: 📅 Set date tag
        run: echo "DATE_TAG=$(date +%d-%m-%Y_%H-%M-%S)" >> $GITHUB_ENV

      - name: 📤 Upload IPA artifact
        uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
        with:
          name: streamyfin-ios-tv-unsigned-ipa-${{ env.DATE_TAG }}
          path: build/*.ipa
          retention-days: 7
