name: Preview Nightly

on:
  schedule:
    # GitHub Actions schedule uses UTC. 16:00 UTC = 北京时间次日 00:00
    - cron: "0 16 * * *"
  workflow_dispatch:

concurrency:
  group: preview-nightly-fixed-release
  cancel-in-progress: true

permissions:
  contents: write

env:
  FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true"
  FIXED_PREVIEW_TAG: nightly-preview
  TARGET_BRANCH: main
  ELECTRON_BUILDER_BINARIES_MIRROR: https://github.com/electron-userland/electron-builder-binaries/releases/download/

jobs:
  prepare:
    runs-on: ubuntu-latest
    outputs:
      should_build: ${{ steps.meta.outputs.should_build }}
      preview_version: ${{ steps.meta.outputs.preview_version }}
    steps:
      - name: Check out git repository
        uses: actions/checkout@v5
        with:
          ref: ${{ env.TARGET_BRANCH }}
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v5
        with:
          node-version: 24
          cache: "npm"

      - name: Decide whether to build and generate preview version
        id: meta
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail

          git fetch origin main --depth=1
          COMMITS_24H="$(git rev-list --count --since='24 hours ago' origin/main)"

          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            SHOULD_BUILD=true
          elif [ "$COMMITS_24H" -gt 0 ]; then
            SHOULD_BUILD=true
          else
            SHOULD_BUILD=false
          fi

          YEAR_2="$(TZ=Asia/Shanghai date +%y)"
          YEARLY_RUN_COUNT=1
          LAST_VERSION="$(gh release view "$FIXED_PREVIEW_TAG" --repo "$GITHUB_REPOSITORY" --json body --jq '.body' 2>/dev/null | grep -Eo '0\.[0-9]{2}\.[0-9]+' | head -n 1 || true)"
          if [[ "$LAST_VERSION" =~ ^0\.([0-9]{2})\.([0-9]+)$ ]]; then
            LAST_YEAR="${BASH_REMATCH[1]}"
            LAST_COUNT="${BASH_REMATCH[2]}"
            if [ "$LAST_YEAR" = "$YEAR_2" ]; then
              YEARLY_RUN_COUNT=$((LAST_COUNT + 1))
            fi
          fi

          PREVIEW_VERSION="0.${YEAR_2}.${YEARLY_RUN_COUNT}"

          echo "should_build=$SHOULD_BUILD" >> "$GITHUB_OUTPUT"
          echo "preview_version=$PREVIEW_VERSION" >> "$GITHUB_OUTPUT"
          echo "Preview version: $PREVIEW_VERSION (commits in last 24h on main: $COMMITS_24H, yearly count: $YEARLY_RUN_COUNT)"

      - name: Recreate fixed preview prerelease
        if: steps.meta.outputs.should_build == 'true'
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          source .github/scripts/release-utils.sh
          recreate_fixed_prerelease "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "$TARGET_BRANCH" "Preview Nightly Build" "预览版发布页"

  preview-mac-arm64:
    needs: prepare
    if: needs.prepare.outputs.should_build == 'true'
    runs-on: macos-14
    steps:
      - name: Check out git repository
        uses: actions/checkout@v5
        with:
          ref: ${{ env.TARGET_BRANCH }}
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v5
        with:
          node-version: 24
          cache: "npm"
      - name: Install Dependencies
        run: npm install

      - name: Ensure mac key helpers are executable
        shell: bash
        run: |
          set -euo pipefail
          for file in \
            resources/key/macos/universal/xkey_helper \
            resources/key/macos/universal/image_scan_helper \
            resources/key/macos/universal/xkey_helper_macos \
            resources/key/macos/universal/libwx_key.dylib
          do
            if [ -f "$file" ]; then
              chmod +x "$file"
              ls -l "$file"
            fi
          done

      - name: Set preview version
        shell: bash
        run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version

      - name: Build Frontend & Type Check
        shell: bash
        run: |
          npx tsc
          npx vite build

      - name: Package macOS arm64 preview artifacts
        env:
          CSC_IDENTITY_AUTO_DISCOVERY: "false"
        shell: bash
        run: |
          set -euo pipefail
          export ELECTRON_BUILDER_BINARIES_MIRROR="https://github.com/electron-userland/electron-builder-binaries/releases/download/"
          echo "Using ELECTRON_BUILDER_BINARIES_MIRROR=$ELECTRON_BUILDER_BINARIES_MIRROR"
          if ! npx electron-builder --mac dmg zip --arm64 --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-arm64.${ext}'; then
            echo "::warning::DMG packaging failed (hdiutil instability on runner). Retrying with ZIP only."
            npx electron-builder --mac zip --arm64 --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-arm64.${ext}'
          fi

      - name: Upload macOS arm64 assets to fixed preview release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          source .github/scripts/release-utils.sh
          assets=()
          while IFS= read -r file; do
            assets+=("$file")
          done < <(find release -maxdepth 1 -type f | sort)
          if [ "${#assets[@]}" -eq 0 ]; then
            echo "No release files found in ./release"
            exit 1
          fi
          upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"

  preview-linux:
    needs: prepare
    if: needs.prepare.outputs.should_build == 'true'
    runs-on: ubuntu-latest
    steps:
      - name: Check out git repository
        uses: actions/checkout@v5
        with:
          ref: ${{ env.TARGET_BRANCH }}
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v5
        with:
          node-version: 24
          cache: "npm"
      - name: Install Dependencies
        run: npm install

      - name: Set preview version
        shell: bash
        run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version

      - name: Build Frontend & Type Check
        shell: bash
        run: |
          npx tsc
          npx vite build

      - name: Package Linux preview artifacts
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          npx electron-builder --linux --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-linux.${ext}'

      - name: Upload Linux assets to fixed preview release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          source .github/scripts/release-utils.sh
          assets=()
          while IFS= read -r file; do
            assets+=("$file")
          done < <(find release -maxdepth 1 -type f | sort)
          if [ "${#assets[@]}" -eq 0 ]; then
            echo "No release files found in ./release"
            exit 1
          fi
          upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"

  preview-win-x64:
    needs: prepare
    if: needs.prepare.outputs.should_build == 'true'
    runs-on: windows-latest
    steps:
      - name: Check out git repository
        uses: actions/checkout@v5
        with:
          ref: ${{ env.TARGET_BRANCH }}
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v5
        with:
          node-version: 24
          cache: "npm"
      - name: Install Dependencies
        run: npm install

      - name: Set preview version
        shell: bash
        run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version

      - name: Build Frontend & Type Check
        shell: bash
        run: |
          npx tsc
          npx vite build

      - name: Package Windows x64 preview artifacts
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          npx electron-builder --win nsis --x64 --publish never '--config.publish.channel=preview' '--config.artifactName=${productName}-preview-x64-Setup.${ext}'

      - name: Upload Windows x64 assets to fixed preview release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          source .github/scripts/release-utils.sh
          assets=()
          while IFS= read -r file; do
            assets+=("$file")
          done < <(find release -maxdepth 1 -type f | sort)
          if [ "${#assets[@]}" -eq 0 ]; then
            echo "No release files found in ./release"
            exit 1
          fi
          upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"

  preview-win-arm64:
    needs: prepare
    if: needs.prepare.outputs.should_build == 'true'
    runs-on: windows-latest
    steps:
      - name: Check out git repository
        uses: actions/checkout@v5
        with:
          ref: ${{ env.TARGET_BRANCH }}
          fetch-depth: 0

      - name: Install Node.js
        uses: actions/setup-node@v5
        with:
          node-version: 24
          cache: "npm"
      - name: Install Dependencies
        run: npm install

      - name: Set preview version
        shell: bash
        run: npm version "${{ needs.prepare.outputs.preview_version }}" --no-git-tag-version --allow-same-version

      - name: Build Frontend & Type Check
        shell: bash
        run: |
          npx tsc
          npx vite build

      - name: Package Windows arm64 preview artifacts
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          npx electron-builder --win nsis --arm64 --publish never '--config.publish.channel=preview-arm64' '--config.artifactName=${productName}-preview-arm64-Setup.${ext}'

      - name: Upload Windows arm64 assets to fixed preview release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail
          source .github/scripts/release-utils.sh
          assets=()
          while IFS= read -r file; do
            assets+=("$file")
          done < <(find release -maxdepth 1 -type f | sort)
          if [ "${#assets[@]}" -eq 0 ]; then
            echo "No release files found in ./release"
            exit 1
          fi
          upload_release_assets_with_retry "$GITHUB_REPOSITORY" "$FIXED_PREVIEW_TAG" "${assets[@]}"

  update-preview-release-notes:
    needs:
      - prepare
      - preview-mac-arm64
      - preview-linux
      - preview-win-x64
      - preview-win-arm64
    if: needs.prepare.outputs.should_build == 'true' && always()
    runs-on: ubuntu-latest
    steps:
      - name: Check out git repository
        uses: actions/checkout@v5
        with:
          ref: ${{ env.TARGET_BRANCH }}
          fetch-depth: 1

      - name: Update preview release notes
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        shell: bash
        run: |
          set -euo pipefail

          TAG="${FIXED_PREVIEW_TAG:-}"
          if [ -z "$TAG" ]; then
            echo "FIXED_PREVIEW_TAG is empty, abort."
            exit 1
          fi
          CURRENT_PREVIEW_VERSION="${{ needs.prepare.outputs.preview_version }}"
          REPO="$GITHUB_REPOSITORY"
          RELEASE_PAGE="https://github.com/$REPO/releases/tag/$TAG"
          echo "Using release tag: $TAG"

          if ! gh api "repos/$REPO/releases/tags/$TAG" >/dev/null 2>&1; then
            echo "Release $TAG not found (possibly all publish jobs failed), skip notes update."
            exit 0
          fi

          ASSETS_JSON="$(gh api "repos/$REPO/releases/tags/$TAG")"

          pick_asset() {
            local pattern="$1"
            echo "$ASSETS_JSON" | jq -r --arg p "$pattern" '[.assets[].name | select(test($p))][0] // ""'
          }

          WINDOWS_ASSET="$(pick_asset "x64.*[.]exe$")"
          if [ -z "$WINDOWS_ASSET" ]; then
            WINDOWS_ASSET="$(echo "$ASSETS_JSON" | jq -r '[.assets[].name | select(test("[.]exe$")) | select(test("arm64") | not)][0] // ""')"
          fi
          WINDOWS_ARM64_ASSET="$(pick_asset "arm64.*[.]exe$")"
          MAC_ASSET="$(pick_asset "[.]dmg$")"
          if [ -z "$MAC_ASSET" ]; then
            MAC_ASSET="$(pick_asset "[.]zip$")"
          fi
          LINUX_TAR_ASSET="$(pick_asset "[.]tar[.]gz$")"
          LINUX_APPIMAGE_ASSET="$(pick_asset "[.]AppImage$")"

          build_link() {
            local name="$1"
            if [ -n "$name" ]; then
              echo "https://github.com/$REPO/releases/download/$TAG/$name"
            fi
          }

          WINDOWS_URL="$(build_link "$WINDOWS_ASSET")"
          WINDOWS_ARM64_URL="$(build_link "$WINDOWS_ARM64_ASSET")"
          MAC_URL="$(build_link "$MAC_ASSET")"
          LINUX_TAR_URL="$(build_link "$LINUX_TAR_ASSET")"
          LINUX_APPIMAGE_URL="$(build_link "$LINUX_APPIMAGE_ASSET")"

          cat > preview_release_notes.md <<EOF
          ## Preview Nightly 说明
          - 该版本为 **预览版**，用于提前体验即将发布的功能与修复。
          - 可能包含尚未完全稳定的改动，不建议长期使用
          - 当前版本号：\`$CURRENT_PREVIEW_VERSION\`

          ## 下载
          - Windows x64: [点击下载](${WINDOWS_URL:-$RELEASE_PAGE})
          - Windows arm64: [点击下载](${WINDOWS_ARM64_URL:-$RELEASE_PAGE})
          - macOS（Apple Silicon）: [点击下载](${MAC_URL:-$RELEASE_PAGE})
          - Linux (.tar.gz): [点击下载](${LINUX_TAR_URL:-$RELEASE_PAGE})
          - Linux (.AppImage): [点击下载](${LINUX_APPIMAGE_URL:-$RELEASE_PAGE})

          ## macOS 安装提示
          - 如果被系统提示已损坏，你需要在终端执行以下命令去除隔离标记：
          - \`xattr -dr com.apple.quarantine "/Applications/WeFlow.app"\`
          - 执行后重新打开 WeFlow。

          > 如某个平台链接暂未生成，请前往[发布页]($RELEASE_PAGE)查看最新资源
          EOF

          update_release_notes() {
            local attempts=5
            local delay_seconds=2
            local i
            for ((i=1; i<=attempts; i++)); do
              if gh release edit "$TAG" --repo "$REPO" --title "Preview Nightly Build" --notes-file preview_release_notes.md --prerelease >/dev/null 2>&1; then
                return 0
              fi
              if [ "$i" -lt "$attempts" ]; then
                echo "Release update failed (attempt $i/$attempts), retry in ${delay_seconds}s..."
                sleep "$delay_seconds"
              fi
            done
            return 1
          }

          update_release_notes
          source .github/scripts/release-utils.sh
          RELEASE_REST_ID="$(wait_for_release_id "$REPO" "$TAG" 12 2)"
          settle_release_state "$REPO" "$RELEASE_REST_ID" "$TAG" 12 2
          print_release_state "$REPO" "$TAG"
