# docs https://github.com/marketplace/actions/create-release
# docs https://github.com/ncipollo/release-action
# docs https://docs.github.com/en/actions/using-jobs/choosing-the-runner-for-a-job#choosing-github-hosted-runners
#
# Architecture: build jobs upload workflow artifacts only. A single
# finalize-release job creates the GitHub release with all assets + body.
# If ANY build job fails, finalize-release is skipped and no release appears.

name: release

on:
  push:
    tags:
      - 'v*'

jobs:
  preflight:
    runs-on: ubuntu-22.04
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Node.js v22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: corepack enable
      - name: Install dependencies
        run: |
          for i in 1 2 3; do
            echo "yarn install attempt $i"
            yarn install --immutable && break
            sleep 5
            [ "$i" = "3" ] && exit 1
          done
      - name: Run Vitest
        run: yarn test --run
      - name: Lint
        run: yarn lint
      - name: Type check
        run: yarn type-check
      - name: Build React app
        run: CI='' NODE_ENV=production yarn build
      - name: Run React Doctor
        run: yarn doctor
      - name: Install Chromium for smoke tests
        run: npx playwright install --with-deps chromium
      - name: Smoke test built web app
        run: node scripts/smoke-web-app.js --start-preview

  linux:
    strategy:
      fail-fast: false
      matrix:
        arch: [x64, arm64]
    runs-on: ubuntu-22.04
    needs: preflight
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Node.js v22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: corepack enable
      - name: Install dependencies
        run: |
          for i in 1 2 3; do
            echo "yarn install attempt $i"
            yarn install --immutable && break
            sleep 5
            [ "$i" = "3" ] && exit 1
          done
      - name: Download IPFS and set permissions
        run: BUILD_ARCH=${{ matrix.arch }} node electron/download-ipfs && sudo chmod +x bin/linux/ipfs
      - name: Build React app
        run: CI='' NODE_ENV=production yarn build
      - name: Build Electron app for Linux (arm64)
        if: matrix.arch == 'arm64'
        run: yarn electron:build:linux:arm64
      - name: Build Electron app for Linux (x64)
        if: matrix.arch == 'x64'
        run: yarn electron:build:linux:x64
      - name: Stage release artifacts
        run: |
          mkdir -p release-assets
          VERSION=$(node -e "console.log(require('./package.json').version)")
          APPIMAGE_PATH=$(find out/make/AppImage -name '*.AppImage' | head -n 1)
          [ -n "$APPIMAGE_PATH" ] || exit 1
          cp "$APPIMAGE_PATH" "release-assets/5chan-${VERSION}-${{ matrix.arch }}.AppImage"
      - name: Create static HTML release archive
        if: matrix.arch == 'x64'
        env:
          RELEASE_MANIFEST_PRIVATE_KEY_PEM: ${{ secrets.RELEASE_MANIFEST_PRIVATE_KEY_PEM }}
          RELEASE_MANIFEST_KEY_ID: 5chan-release-p256-2026-05
        run: |
          VERSION=$(node -e "console.log(require('./package.json').version)")
          HTML_ARCHIVE_DIR="5chan-$VERSION-html"
          rm -rf "$HTML_ARCHIVE_DIR"
          yarn release:manifest --build-dir build --out-dir release-assets
          cp -R build "$HTML_ARCHIVE_DIR"
          cp release-assets/5chan-release-manifest.json "$HTML_ARCHIVE_DIR/5chan-release-manifest.json"
          cp release-assets/5chan-release-manifest.sig.json "$HTML_ARCHIVE_DIR/5chan-release-manifest.sig.json"
          zip -r "release-assets/${HTML_ARCHIVE_DIR}.zip" "$HTML_ARCHIVE_DIR"
          rm -rf "$HTML_ARCHIVE_DIR"
      - name: List release assets
        run: ls -la release-assets
      - uses: actions/upload-artifact@v4
        with:
          name: release-linux-${{ matrix.arch }}
          path: release-assets/

  mac:
    strategy:
      fail-fast: false
      matrix:
        include:
          - runner: macos-15-intel # Intel x64
            arch: x64
          - runner: macos-latest # Apple Silicon arm64
            arch: arm64
    runs-on: ${{ matrix.runner }}
    needs: preflight
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Node.js v22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: corepack enable
      - name: Setup Python 3.12
        uses: actions/setup-python@v5
        with:
          python-version: '3.12'
      - run: pip install setuptools
      - name: Install dependencies
        run: |
          for i in 1 2 3; do
            echo "yarn install attempt $i"
            yarn install --immutable && break
            sleep 5
            [ "$i" = "3" ] && exit 1
          done
      - name: Download IPFS and set permissions
        run: node electron/download-ipfs && sudo chmod +x bin/mac/ipfs
      - name: Build React app
        run: CI='' NODE_ENV=production yarn build
      - name: Build Electron app for Mac
        env:
          CSC_IDENTITY_AUTO_DISCOVERY: 'false'
        run: |
          if [ "${{ matrix.arch }}" = "arm64" ]; then
            yarn electron:build:mac:arm64
          else
            yarn electron:build:mac:x64
          fi
      - name: Stage release artifacts
        run: |
          mkdir -p release-assets
          VERSION=$(node -e "console.log(require('./package.json').version)")
          DMG_PATH=$(find out/make -maxdepth 1 -name '*.dmg' | head -n 1)
          ZIP_PATH=$(find out/make/zip -name '*.zip' | head -n 1)
          [ -n "$DMG_PATH" ] || exit 1
          [ -n "$ZIP_PATH" ] || exit 1
          cp "$DMG_PATH" "release-assets/5chan-${VERSION}-${{ matrix.arch }}.dmg"
          cp "$ZIP_PATH" "release-assets/5chan-${VERSION}-${{ matrix.arch }}.zip"
      - name: List release assets
        run: ls -la release-assets
      - uses: actions/upload-artifact@v4
        with:
          name: release-mac-${{ matrix.arch }}
          path: release-assets/

  windows:
    runs-on: windows-2022
    needs: preflight
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Node.js v22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: corepack enable
      - name: Resolve Yarn cache path
        id: yarn-cache
        shell: bash
        run: echo "dir=$(corepack yarn config get cacheFolder)" >> "$GITHUB_OUTPUT"
      - name: Cache Yarn package tarballs
        uses: actions/cache@v4
        with:
          path: ${{ steps.yarn-cache.outputs.dir }}
          key: ${{ runner.os }}-yarn-v1-${{ hashFiles('yarn.lock', 'package.json', '.yarnrc.yml') }}
          restore-keys: ${{ runner.os }}-yarn-v1-
      - name: Cache electron binaries
        uses: actions/cache@v4
        with:
          path: ~/AppData/Local/electron/Cache
          key: ${{ runner.os }}-electron-v2-${{ hashFiles('**/yarn.lock') }}
          restore-keys: ${{ runner.os }}-electron-v2-
      - name: Install dependencies
        shell: bash
        run: |
          for i in 1 2 3; do
            echo "yarn install attempt $i"
            yarn install --immutable && break
            sleep 5
            [ "$i" = "3" ] && exit 1
          done
      - name: Build React app
        run: npx cross-env NODE_ENV=production yarn build
      - name: Build Electron app for Windows (x64)
        run: yarn electron:build:windows
      - name: Stage release artifacts
        shell: bash
        run: |
          mkdir -p release-assets
          VERSION=$(node -e "console.log(require('./package.json').version)")
          SETUP_EXE_PATH=$(find out/make -iname '*setup*.exe' | head -n 1)
          [ -n "$SETUP_EXE_PATH" ] || exit 1
          cp "$SETUP_EXE_PATH" "release-assets/5chan-${VERSION}-x64.Setup.exe"
      - name: List release assets
        shell: bash
        run: ls -la release-assets
      - uses: actions/upload-artifact@v4
        with:
          name: release-windows
          path: release-assets/

  android:
    runs-on: ubuntu-22.04
    needs: preflight
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - uses: actions/setup-java@v4
        with:
          distribution: 'zulu'
          java-version: '17'
      - uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: corepack enable
      - run: sudo apt-get install -y apksigner zipalign
      - name: Install dependencies
        run: |
          for i in 1 2 3; do
            echo "yarn install attempt $i"
            yarn install --immutable && break
            sleep 5
            [ "$i" = "3" ] && exit 1
          done
      - name: Build React app
        run: CI='' NODE_ENV=production yarn build
      - name: Set Android versionCode and versionName
        run: |
          VERSION=$(node -e "console.log(require('./package.json').version)")
          VERSION_CODE=$(node -e "const [major = 0, minor = 0, patch = 0] = require('./package.json').version.replace(/^v/, '').split('-')[0].split('.').map(Number); console.log((major * 10000) + (minor * 100) + patch)")
          echo "APP_VERSION_NAME=${VERSION}" >> "$GITHUB_ENV"
          echo "APP_VERSION_CODE=${VERSION_CODE}" >> "$GITHUB_ENV"
          echo "Android versionName=${VERSION} versionCode=${VERSION_CODE}"
      - name: Sync Capacitor
        run: npx cap sync android
      - name: Build APK
        run: |
          for i in 1 2 3; do
            echo "gradlew assembleGithubRelease attempt $i"
            (cd android && ./gradlew assembleGithubRelease -PAPP_VERSION_NAME="${APP_VERSION_NAME}" -PAPP_VERSION_CODE="${APP_VERSION_CODE}" --stacktrace) && break
            sleep 10
            [ "$i" = "3" ] && exit 1
          done
      - name: Optimize APK
        run: cd android/app/build/outputs/apk/github/release && zipalign 4 app-github-release-unsigned.apk app-github-release-unsigned-zip.apk
      - name: Sign APK
        run: cd android/app/build/outputs/apk/github/release && apksigner sign --ks ../../../../../../plebbit.keystore --ks-pass pass:${{ secrets.PLEBBIT_REACT_KEYSTORE_PASSWORD }} --ks-key-alias release --out app-github-release-signed.apk app-github-release-unsigned-zip.apk
      - name: Stage release artifacts
        run: |
          mkdir -p release-assets
          VERSION=$(node -e "console.log(require('./package.json').version)")
          mv android/app/build/outputs/apk/github/release/app-github-release-signed.apk "release-assets/5chan-${VERSION}.apk"
      - name: List release assets
        run: ls -la release-assets
      - uses: actions/upload-artifact@v4
        with:
          name: release-android
          path: release-assets/

  finalize-release:
    runs-on: ubuntu-22.04
    needs: [linux, mac, windows, android]
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0
      - name: Setup Node.js v22
        uses: actions/setup-node@v4
        with:
          node-version: 22
      - run: corepack enable
      - name: Install dependencies
        run: |
          for i in 1 2 3; do
            echo "yarn install attempt $i"
            yarn install --immutable && break
            sleep 5
            [ "$i" = "3" ] && exit 1
          done
      - name: Download all release artifacts
        uses: actions/download-artifact@v4
        with:
          pattern: release-*
          path: release-assets
          merge-multiple: true
      - name: List all release assets
        run: ls -la release-assets
      - name: Populate dist for release-body script
        run: |
          mkdir -p dist
          cp release-assets/* dist/
      - name: Generate release body
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          GITHUB_REPOSITORY: ${{ github.repository }}
          GITHUB_REF_NAME: ${{ github.ref_name }}
        run: node scripts/release-body > release-body.txt
      - name: Check Vercel deployment token
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
        run: |
          if [ -z "${VERCEL_TOKEN:-}" ]; then
            echo "::error::VERCEL_TOKEN is required to deploy the release HTML archive to Vercel Production."
            exit 1
          fi
      - name: Create GitHub release
        uses: ncipollo/release-action@v1
        with:
          artifacts: 'release-assets/*'
          bodyFile: "release-body.txt"
          allowUpdates: true
          token: ${{ secrets.GITHUB_TOKEN }}
      - name: Deploy web release to Vercel Production
        env:
          VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
          VERCEL_ORG_ID: team_drHWHjDIQypSvbjZ1F468uLm
          VERCEL_PROJECT_ID: prj_oeEtip9l1zUvJF00QdhMXpXn2CH7
        run: |
          if [ -z "${VERCEL_TOKEN:-}" ]; then
            echo "::error::VERCEL_TOKEN is required to deploy the release HTML archive to Vercel Production."
            exit 1
          fi

          VERSION="${GITHUB_REF_NAME#v}"
          RELEASE_ASSET="release-assets/5chan-${VERSION}-html.zip"
          STAGED_DIR=$(node scripts/prepare-vercel-release-deploy.mjs --tag "$GITHUB_REF_NAME" --asset "$RELEASE_ASSET" --out-dir vercel-release-deploy)
          corepack yarn dlx vercel@50.23.2 deploy "$STAGED_DIR" \
            --prebuilt \
            --prod \
            --yes \
            --force \
            --archive=tgz \
            --token "$VERCEL_TOKEN" \
            --meta source=github-release \
            --meta releaseTag="$GITHUB_REF_NAME" \
            --meta releaseAsset="5chan-${VERSION}-html.zip"
