name: Release

on:
  push:
    tags:
      - 'v*'

permissions:
  contents: write

concurrency:
  group: release-${{ github.ref_name }}
  cancel-in-progress: true

jobs:
  release:
    runs-on: ${{ matrix.os }}
    strategy:
      matrix:
        include:
          - os: windows-2022
          - os: ubuntu-22.04
          - os: macos-14

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'

      - name: Setup Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Add macOS targets
        if: runner.os == 'macOS'
        run: |
          rustup target add aarch64-apple-darwin x86_64-apple-darwin

      - name: Install Linux system deps
        if: runner.os == 'Linux'
        shell: bash
        run: |
          set -euxo pipefail
          sudo apt-get update
          # Core build tools and pkg-config
          sudo apt-get install -y --no-install-recommends \
            build-essential \
            pkg-config \
            curl \
            wget \
            file \
            patchelf \
            libssl-dev
          # GTK/GLib stack for gdk-3.0, glib-2.0, gio-2.0
          sudo apt-get install -y --no-install-recommends \
            libgtk-3-dev \
            librsvg2-dev \
            libayatana-appindicator3-dev
          # WebKit2GTK (version differs across Ubuntu images; try 4.1 then 4.0)
          sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.1-dev \
            || sudo apt-get install -y --no-install-recommends libwebkit2gtk-4.0-dev
          # libsoup also changed major version; prefer 3.0 with fallback to 2.4
          sudo apt-get install -y --no-install-recommends libsoup-3.0-dev \
            || sudo apt-get install -y --no-install-recommends libsoup2.4-dev

      - name: Setup pnpm
        uses: pnpm/action-setup@v2
        with:
          version: 10.12.3
          run_install: false

      - name: Get pnpm store directory
        id: pnpm-store
        shell: bash
        run: echo "path=$(pnpm store path --silent)" >> $GITHUB_OUTPUT

      - name: Setup pnpm cache
        uses: actions/cache@v4
        with:
          path: ${{ steps.pnpm-store.outputs.path }}
          key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
          restore-keys: ${{ runner.os }}-pnpm-store-

      - name: Install frontend deps
        run: pnpm install --frozen-lockfile

      - name: Prepare Tauri signing key
        shell: bash
        run: |
          # 调试：检查 Secret 是否存在
          if [ -z "${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}" ]; then
            echo "❌ TAURI_SIGNING_PRIVATE_KEY Secret 为空或不存在" >&2
            echo "请检查 GitHub 仓库 Settings > Secrets and variables > Actions" >&2
            exit 1
          fi
          
          RAW="${{ secrets.TAURI_SIGNING_PRIVATE_KEY }}"
          # 目标：提供正确的私钥“文件路径”给 Tauri CLI，避免内容解码歧义
          KEY_PATH="$RUNNER_TEMP/tauri_signing.key"
          # 情况 1：原始两行文本（第一行以 "untrusted comment:" 开头）
          if echo "$RAW" | head -n1 | grep -q '^untrusted comment:'; then
            printf '%s\n' "$RAW" > "$KEY_PATH"
            echo "✅ 使用原始两行密钥文件格式"
          else
            # 情况 2：整体被 base64 包裹（解包后应当是两行）
            if DECODED=$(printf '%s' "$RAW" | (base64 --decode 2>/dev/null || base64 -D 2>/dev/null)) \
               && echo "$DECODED" | head -n1 | grep -q '^untrusted comment:'; then
              printf '%s\n' "$DECODED" > "$KEY_PATH"
              echo "✅ 成功解码 base64 包裹密钥，已还原为两行文件"
            else
              # 情况 3：已是第二行（纯 Base64 一行）→ 构造两行文件
              if echo "$RAW" | grep -Eq '^[A-Za-z0-9+/=]+$'; then
                ONE=$(printf '%s' "$RAW" | tr -d '\r\n')
                printf '%s\n%s\n' "untrusted comment: tauri signing key" "$ONE" > "$KEY_PATH"
                echo "✅ 使用一行 Base64 私钥，已构造两行文件"
              else
                echo "❌ TAURI_SIGNING_PRIVATE_KEY 格式无法识别：既不是两行原文，也不是其 base64，亦非一行 base64" >&2
                echo "密钥前10个字符: $(echo "$RAW" | head -c 10)..." >&2
                exit 1
              fi
            fi
          fi
          # 将“完整两行内容”作为环境变量注入（Tauri 支持传入完整私钥文本或文件路径）
          # 使用多行写入语法，保持换行以便解析
          # 将完整两行私钥内容进行 base64 编码，作为单行内容注入环境变量
          if command -v base64 >/dev/null 2>&1; then
            KEY_B64=$(base64 < "$KEY_PATH" | tr -d '\r\n')
          elif command -v openssl >/dev/null 2>&1; then
            KEY_B64=$(openssl base64 -A -in "$KEY_PATH")
          else
            KEY_B64=$(KEY_PATH="$KEY_PATH" node -e "process.stdout.write(require('fs').readFileSync(process.env.KEY_PATH).toString('base64'))")
          fi
          if [ -z "$KEY_B64" ]; then
            echo "❌ 无法生成私钥 base64 内容" >&2
            exit 1
          fi
          echo "TAURI_SIGNING_PRIVATE_KEY=$KEY_B64" >> "$GITHUB_ENV"
          if [ -n "${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" ]; then
            echo "TAURI_SIGNING_PRIVATE_KEY_PASSWORD=${{ secrets.TAURI_SIGNING_PRIVATE_KEY_PASSWORD }}" >> $GITHUB_ENV
          fi
          echo "✅ Tauri signing key prepared"

      - name: Build Tauri App (macOS)
        if: runner.os == 'macOS'
        run: pnpm tauri build --target universal-apple-darwin

      - name: Build Tauri App (Windows)
        if: runner.os == 'Windows'
        run: pnpm tauri build

      - name: Build Tauri App (Linux)
        if: runner.os == 'Linux'
        run: pnpm tauri build

      - name: Prepare macOS Assets
        if: runner.os == 'macOS'
        shell: bash
        run: |
          set -euxo pipefail
          mkdir -p release-assets
          echo "Looking for updater artifact (.tar.gz) and .app for zip..."
          TAR_GZ=""; APP_PATH=""
          for path in \
            "src-tauri/target/universal-apple-darwin/release/bundle/macos" \
            "src-tauri/target/aarch64-apple-darwin/release/bundle/macos" \
            "src-tauri/target/x86_64-apple-darwin/release/bundle/macos" \
            "src-tauri/target/release/bundle/macos"; do
            if [ -d "$path" ]; then
              [ -z "$TAR_GZ" ] && TAR_GZ=$(find "$path" -maxdepth 1 -name "*.tar.gz" -type f | head -1 || true)
              [ -z "$APP_PATH" ] && APP_PATH=$(find "$path" -maxdepth 1 -name "*.app" -type d | head -1 || true)
            fi
          done
          if [ -z "$TAR_GZ" ]; then
            echo "No macOS .tar.gz updater artifact found" >&2
            exit 1
          fi
          cp "$TAR_GZ" release-assets/
          [ -f "$TAR_GZ.sig" ] && cp "$TAR_GZ.sig" release-assets/ || echo ".sig for macOS not found yet"
          echo "macOS updater artifact copied: $(basename "$TAR_GZ")"
          if [ -n "$APP_PATH" ]; then
            APP_DIR=$(dirname "$APP_PATH"); APP_NAME=$(basename "$APP_PATH")
            cd "$APP_DIR"
            ditto -c -k --sequesterRsrc --keepParent "$APP_NAME" "CC-Switch-macOS.zip"
            mv "CC-Switch-macOS.zip" "$GITHUB_WORKSPACE/release-assets/"
            echo "macOS zip ready: CC-Switch-macOS.zip"
          else
            echo "No .app found to zip (optional)" >&2
          fi

      - name: Prepare Windows Assets
        if: runner.os == 'Windows'
        shell: pwsh
        run: |
          $ErrorActionPreference = 'Stop'
          New-Item -ItemType Directory -Force -Path release-assets | Out-Null
          # 仅打包 MSI 安装器 + .sig（用于 Updater）
          $msi = Get-ChildItem -Path 'src-tauri/target/release/bundle/msi' -Recurse -Include *.msi -ErrorAction SilentlyContinue | Select-Object -First 1
          if ($null -eq $msi) {
            # 兜底：全局搜索 .msi
            $msi = Get-ChildItem -Path 'src-tauri/target/release/bundle' -Recurse -Include *.msi -ErrorAction SilentlyContinue | Select-Object -First 1
          }
          if ($null -ne $msi) {
            $dest = 'CC-Switch-Setup.msi'
            Copy-Item $msi.FullName (Join-Path release-assets $dest)
            Write-Host "Installer copied: $dest"
            $sigPath = "$($msi.FullName).sig"
            if (Test-Path $sigPath) {
              Copy-Item $sigPath (Join-Path release-assets ("$dest.sig"))
              Write-Host "Signature copied: $dest.sig"
            } else {
              Write-Warning "Signature not found for $($msi.Name)"
            }
          } else {
            Write-Warning 'No Windows MSI installer found'
          }
          # 绿色版（portable）：仅可执行文件打 zip（不参与 Updater）
          $exeCandidates = @(
            'src-tauri/target/release/cc-switch.exe',
            'src-tauri/target/x86_64-pc-windows-msvc/release/cc-switch.exe'
          )
          $exePath = $exeCandidates | Where-Object { Test-Path $_ } | Select-Object -First 1
          if ($null -ne $exePath) {
            $portableDir = 'release-assets/CC-Switch-Portable'
            New-Item -ItemType Directory -Force -Path $portableDir | Out-Null
            Copy-Item $exePath $portableDir
            Compress-Archive -Path "$portableDir/*" -DestinationPath 'release-assets/CC-Switch-Windows-Portable.zip' -Force
            Remove-Item -Recurse -Force $portableDir
            Write-Host 'Windows portable zip created'
          } else {
            Write-Warning 'Portable exe not found'
          }

      - name: Prepare Linux Assets
        if: runner.os == 'Linux'
        shell: bash
        run: |
          set -euxo pipefail
          mkdir -p release-assets
          # Updater artifact: AppImage（含对应 .sig）
          APPIMAGE=$(find src-tauri/target/release/bundle -name "*.AppImage" | head -1 || true)
          if [ -n "$APPIMAGE" ]; then
            cp "$APPIMAGE" release-assets/
            [ -f "$APPIMAGE.sig" ] && cp "$APPIMAGE.sig" release-assets/ || echo ".sig for AppImage not found"
            echo "AppImage copied"
          else
            echo "No AppImage found under target/release/bundle" >&2
          fi
          # 额外上传 .deb（用于手动安装，不参与 Updater）
          DEB=$(find src-tauri/target/release/bundle -name "*.deb" | head -1 || true)
          if [ -n "$DEB" ]; then
            cp "$DEB" release-assets/
            echo "Deb package copied"
          else
            echo "No .deb found (optional)"
          fi

      - name: List prepared assets
        shell: bash
        run: |
          ls -la release-assets || true

      - name: Collect Signatures
        shell: bash
        run: |
          set -euo pipefail
          echo "Collected signatures (if any alongside artifacts):"
          ls -la release-assets/*.sig || echo "No signatures found"

      - name: Upload Release Assets
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ github.ref_name }}
          name: CC Switch ${{ github.ref_name }}
          prerelease: true
          body: |
            ## CC Switch ${{ github.ref_name }}

            Claude Code 供应商切换工具

            ### 下载

            - macOS: `CC-Switch-macOS.zip`（解压即用）
            - Windows: `CC-Switch-Setup.msi`（安装版）；`CC-Switch-Windows-Portable.zip`（绿色版）
            - Linux: `*.deb`（Debian/Ubuntu 安装包）

            ---
            提示：macOS 如遇“已损坏”提示，可在终端执行：`xattr -cr "/Applications/CC Switch.app"`
          files: release-assets/*
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: List generated bundles (debug)
        if: always()
        shell: bash
        run: |
          echo "Listing bundles in src-tauri/target..."
          find src-tauri/target -maxdepth 4 -type f -name "*.*" 2>/dev/null || true

  assemble-latest-json:
    name: Assemble latest.json
    runs-on: ubuntu-22.04
    needs: release
    permissions:
      contents: write
    steps:
      - name: Prepare GH
        run: |
          gh --version || (type -p curl >/dev/null && sudo apt-get update && sudo apt-get install -y gh || true)
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
      - name: Download all release assets
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euxo pipefail
          TAG="${GITHUB_REF_NAME}"
          mkdir -p dl
          gh release download "$TAG" --dir dl --repo "$GITHUB_REPOSITORY"
          ls -la dl || true
      - name: Generate latest.json
        env:
          REPO: ${{ github.repository }}
          TAG: ${{ github.ref_name }}
        run: |
          set -euo pipefail
          VERSION="${TAG#v}"
          PUB_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ)
          base_url="https://github.com/$REPO/releases/download/$TAG"
          # 初始化空平台映射
          mac_url=""; mac_sig=""
          win_url=""; win_sig=""
          linux_url=""; linux_sig=""
          shopt -s nullglob
          for sig in dl/*.sig; do
            base=${sig%.sig}
            fname=$(basename "$base")
            url="$base_url/$fname"
            sig_content=$(cat "$sig")
            case "$fname" in
              *.tar.gz)
                # 视为 macOS updater artifact
                mac_url="$url"; mac_sig="$sig_content";;
              *.AppImage|*.appimage)
                linux_url="$url"; linux_sig="$sig_content";;
              *.msi|*.exe)
                win_url="$url"; win_sig="$sig_content";;
            esac
          done
          # 构造 JSON（仅包含存在的目标）
          tmp_json=$(mktemp)
          {
            echo '{'
            echo "  \"version\": \"$VERSION\",";
            echo "  \"notes\": \"Release $TAG\",";
            echo "  \"pub_date\": \"$PUB_DATE\",";
            echo '  "platforms": {'
            first=1
            if [ -n "$mac_url" ] && [ -n "$mac_sig" ]; then
              # 为兼容 arm64 / x64，重复写入两个键，指向同一 universal 包
              for key in darwin-aarch64 darwin-x86_64; do
                [ $first -eq 0 ] && echo ','
                echo "    \"$key\": {\"signature\": \"$mac_sig\", \"url\": \"$mac_url\"}"
                first=0
              done
            fi
            if [ -n "$win_url" ] && [ -n "$win_sig" ]; then
              [ $first -eq 0 ] && echo ','
              echo "    \"windows-x86_64\": {\"signature\": \"$win_sig\", \"url\": \"$win_url\"}"
              first=0
            fi
            if [ -n "$linux_url" ] && [ -n "$linux_sig" ]; then
              [ $first -eq 0 ] && echo ','
              echo "    \"linux-x86_64\": {\"signature\": \"$linux_sig\", \"url\": \"$linux_url\"}"
              first=0
            fi
            echo '  }'
            echo '}'
          } > "$tmp_json"
          echo "Generated latest.json:" && cat "$tmp_json"
          mv "$tmp_json" latest.json
      - name: Upload latest.json to release
        env:
          GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
        run: |
          set -euxo pipefail
          gh release upload "$GITHUB_REF_NAME" latest.json --clobber --repo "$GITHUB_REPOSITORY"
