name: Build Binaries

# Build multi-platform binaries on release or manual trigger
# Produces distributable packages for Linux, macOS, and Windows
on:
  release:
    types: [published]
  workflow_dispatch:

# Environment variables for build configuration
env:
  GO_VERSION: "1.25.7"
  NODE_VERSION: "22"
  PNPM_VERSION: "10"
  ARTIFACT_RETENTION_DAYS: 60
  # Artifact naming: {ARTIFACT_PREFIX}_{version}_{os}_{arch}.tar.gz|zip
  ARTIFACT_PREFIX: memos

jobs:
  # Job 1: Extract version information
  # - For git tags: use tag version (e.g., v0.28.1 -> 0.28.1)
  # - For branches: use branch-name-shortSHA format
  prepare:
    name: Extract Version
    runs-on: ubuntu-latest
    outputs:
      version: ${{ steps.version.outputs.version }}
    steps:
      - name: Checkout code
        uses: actions/checkout@v6
        with:
          fetch-depth: 0  # Full history for git describe

      - name: Extract version
        id: version
        run: |
          # Try to get version from git tag
          TAG=$(git describe --tags --exact-match 2>/dev/null || echo "")
          if [ -n "$TAG" ]; then
            echo "version=${TAG#v}" >> $GITHUB_OUTPUT
            echo "Version from tag: ${TAG#v}"
          else
            # Use branch name + short SHA
            BRANCH="${GITHUB_REF_NAME//\//-}"
            SHORT_SHA="${GITHUB_SHA:0:7}"
            echo "version=${BRANCH}-${SHORT_SHA}" >> $GITHUB_OUTPUT
            echo "Version from branch: ${BRANCH}-${SHORT_SHA}"
          fi

  # Job 2: Build frontend assets
  # - Builds React frontend with Vite
  # - Produces static files that will be embedded in Go binary
  # - Shared across all platform builds
  build-frontend:
    name: Build Frontend
    needs: prepare
    runs-on: ubuntu-latest
    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup pnpm
        uses: pnpm/action-setup@v4.2.0
        with:
          version: ${{ env.PNPM_VERSION }}

      - name: Setup Node.js
        uses: actions/setup-node@v6
        with:
          node-version: ${{ env.NODE_VERSION }}
          cache: pnpm
          cache-dependency-path: web/pnpm-lock.yaml

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

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

      - name: Install dependencies
        working-directory: web
        run: pnpm install --frozen-lockfile

      - name: Build frontend
        working-directory: web
        run: pnpm release

      - name: Upload frontend artifacts
        uses: actions/upload-artifact@v6
        with:
          name: frontend-dist
          path: server/router/frontend/dist
          retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}

  # Job 3: Build Go binaries for multiple platforms
  # - Cross-compiles using native Go toolchain
  # - Embeds frontend assets built in previous job
  # - Produces static binaries with no external dependencies
  # - Packages as tar.gz (Unix) or zip (Windows)
  build-binaries:
    name: Build ${{ matrix.goos }}-${{ matrix.goarch }}${{ matrix.goarm && format('v{0}', matrix.goarm) || '' }}
    needs: [prepare, build-frontend]
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        include:
          # Linux targets
          - goos: linux
            goarch: amd64
          - goos: linux
            goarch: arm64
          - goos: linux
            goarch: arm
            goarm: "7"
          # macOS targets
          - goos: darwin
            goarch: amd64  # Intel Macs
          - goos: darwin
            goarch: arm64  # Apple Silicon
          # Windows targets
          - goos: windows
            goarch: amd64

    steps:
      - name: Checkout code
        uses: actions/checkout@v6

      - name: Setup Go
        uses: actions/setup-go@v6
        with:
          go-version: ${{ env.GO_VERSION }}
          cache: true

      - name: Download frontend artifacts
        uses: actions/download-artifact@v7
        with:
          name: frontend-dist
          path: server/router/frontend/dist

      - name: Build binary
        env:
          GOOS: ${{ matrix.goos }}
          GOARCH: ${{ matrix.goarch }}
          GOARM: ${{ matrix.goarm }}
          CGO_ENABLED: "0"
        run: |
          # Determine output binary name
          OUTPUT_NAME="memos"
          if [ "$GOOS" = "windows" ]; then
            OUTPUT_NAME="memos.exe"
          fi

          mkdir -p build

          # Build static binary with optimizations
          go build \
            -trimpath \
            -ldflags="-s -w -extldflags '-static'" \
            -tags netgo,osusergo \
            -o "build/${OUTPUT_NAME}" \
            ./cmd/memos

          echo "✓ Built: build/${OUTPUT_NAME}"
          ls -lh build/

      - name: Package binary
        id: package
        env:
          VERSION: ${{ needs.prepare.outputs.version }}
          GOOS: ${{ matrix.goos }}
          GOARCH: ${{ matrix.goarch }}
          GOARM: ${{ matrix.goarm }}
        run: |
          cd build

          # Construct package name: {prefix}_{version}_{os}_{arch}[v{arm_version}]
          PACKAGE_NAME="${ARTIFACT_PREFIX}_${VERSION}_${GOOS}_${GOARCH}"
          if [ -n "$GOARM" ]; then
            PACKAGE_NAME="${PACKAGE_NAME}v${GOARM}"
          fi

          # Package based on platform
          if [ "$GOOS" = "windows" ]; then
            ARTIFACT_NAME="${PACKAGE_NAME}.zip"
            zip -q "${ARTIFACT_NAME}" memos.exe
          else
            ARTIFACT_NAME="${PACKAGE_NAME}.tar.gz"
            tar czf "${ARTIFACT_NAME}" memos
          fi

          # Output for next step
          echo "ARTIFACT_NAME=${ARTIFACT_NAME}" >> $GITHUB_ENV
          echo "✓ Package created: ${ARTIFACT_NAME} ($(du -h "${ARTIFACT_NAME}" | cut -f1))"

      - name: Upload binary artifact
        uses: actions/upload-artifact@v6
        with:
          name: ${{ env.ARTIFACT_NAME }}
          path: build/${{ env.ARTIFACT_NAME }}
          retention-days: ${{ env.ARTIFACT_RETENTION_DAYS }}

  # Job 4: Upload artifacts to GitHub Release
  # - Only runs when triggered by a release publish event
  # - Downloads all built artifacts and attaches them to the release
  release:
    name: Upload Release Assets
    needs: build-binaries
    if: github.event_name == 'release'
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Download all artifacts
        uses: actions/download-artifact@v7
        with:
          path: artifacts
          pattern: ${{ env.ARTIFACT_PREFIX }}_*
          merge-multiple: true

      - name: Upload to GitHub Release
        uses: softprops/action-gh-release@v2
        with:
          files: artifacts/*

