name: Docker Build and Publish

on:
  push:
    branches:
      - next

jobs:
  # Prepare metadata and tags for all builds
  prepare:
    runs-on: ubuntu-latest
    outputs:
      is_release: ${{ steps.check-release.outputs.is_release }}
      release_tag: ${{ steps.check-release.outputs.release_tag }}
      tags: ${{ steps.tags.outputs.tags }}
      image: ${{ steps.tags.outputs.image }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - name: Check if this commit is a release
        id: check-release
        run: |
          git fetch --tags

          # Check if this is a release-please commit
          if git log -1 --pretty=%B | grep -q "release-please--branches--next"; then
            echo "This is a release commit, waiting for tag..."
            # Wait up to 60 seconds for release-please to create the tag
            for i in {1..12}; do
              sleep 5
              git fetch --tags
              TAG=$(git tag --points-at HEAD | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 || echo "")
              if [[ -n "$TAG" ]]; then
                echo "is_release=true" >> $GITHUB_OUTPUT
                echo "release_tag=$TAG" >> $GITHUB_OUTPUT
                echo "Found release tag: $TAG"
                exit 0
              fi
              echo "Waiting for tag... ($i/12)"
            done
            echo "ERROR: Release commit but no tag found after 60s"
            exit 1
          else
            # Regular commit, check for tag immediately
            TAG=$(git tag --points-at HEAD | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -n1 || echo "")
            if [[ -n "$TAG" ]]; then
              echo "is_release=true" >> $GITHUB_OUTPUT
              echo "release_tag=$TAG" >> $GITHUB_OUTPUT
              echo "This is a release: $TAG"
            else
              echo "is_release=false" >> $GITHUB_OUTPUT
              echo "This is a regular commit"
            fi
          fi

      - name: Compute tags
        id: tags
        run: |
          IMAGE="ghcr.io/${{ github.repository }}"

          if [[ "${{ steps.check-release.outputs.is_release }}" == "true" ]]; then
            # This is a release: use semver tags + latest
            TAG="${{ steps.check-release.outputs.release_tag }}"
            VERSION="${TAG#v}"
            MAJOR=$(echo "$VERSION" | cut -d. -f1)
            MINOR=$(echo "$VERSION" | cut -d. -f2)
            TAGS="${VERSION},${MAJOR}.${MINOR},${MAJOR},latest"
            echo "Building RELEASE with tags: $TAGS"
          else
            # Regular commit: use SHA tags only (no latest)
            SHORT_SHA="${GITHUB_SHA:0:7}"
            TAGS="sha-${SHORT_SHA}"
            echo "Building COMMIT with tags: $TAGS"
          fi
          echo "tags=$TAGS" >> $GITHUB_OUTPUT
          echo "image=$IMAGE" >> $GITHUB_OUTPUT

  # Build natively on each platform (faster, no QEMU emulation)
  build:
    needs: prepare
    runs-on: ${{ matrix.runner }}
    permissions:
      contents: read
      packages: write
    strategy:
      matrix:
        include:
          - platform: linux/amd64
            runner: ubuntu-latest
          - platform: linux/arm64
            runner: ubuntu-24.04-arm

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

      - name: Setup Turborepo cache
        uses: actions/cache@v4
        with:
          path: .turbo
          key: ${{ runner.os }}-${{ runner.arch }}-turbo-${{ github.sha }}
          restore-keys: |
            ${{ runner.os }}-${{ runner.arch }}-turbo-

      - name: Free disk space
        run: |
          sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc /opt/hostedtoolcache/CodeQL
          docker system prune -af --volumes

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ needs.prepare.outputs.image }}

      - name: Build and push by digest
        id: build
        uses: docker/build-push-action@v6
        with:
          context: .
          platforms: ${{ matrix.platform }}
          push: true
          labels: ${{ steps.meta.outputs.labels }}
          outputs: type=image,name=${{ needs.prepare.outputs.image }},push-by-digest=true,name-canonical=true,push=true
          cache-from: type=gha,scope=${{ matrix.platform }}
          cache-to: type=gha,mode=max,scope=${{ matrix.platform }}
          build-args: |
            BUILDTIME=${{ fromJSON(steps.meta.outputs.json).labels['org.opencontainers.image.created'] }}
            VERSION=${{ github.ref_name }}
            REVISION=${{ github.sha }}

      - name: Export digest
        run: |
          mkdir -p /tmp/digests
          digest="${{ steps.build.outputs.digest }}"
          touch "/tmp/digests/${digest#sha256:}"

      - name: Upload digest
        uses: actions/upload-artifact@v4
        with:
          name: digests-${{ strategy.job-index }}
          path: /tmp/digests/*
          if-no-files-found: error
          retention-days: 1

  # Merge platform-specific images into multi-arch manifest
  merge:
    needs: [ prepare, build ]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write
      attestations: write
      id-token: write
    steps:
      - name: Download digests
        uses: actions/download-artifact@v4
        with:
          path: /tmp/digests
          pattern: digests-*
          merge-multiple: true

      - name: Set up Docker Buildx
        uses: docker/setup-buildx-action@v3

      - name: Log in to GHCR
        uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Create manifest list and push
        working-directory: /tmp/digests
        run: |
          IMAGE="${{ needs.prepare.outputs.image }}"
          TAGS="${{ needs.prepare.outputs.tags }}"

          # Convert comma-separated tags to array and create docker tag arguments
          TAG_ARGS=""
          IFS=',' read -ra TAG_ARRAY <<< "$TAGS"
          for tag in "${TAG_ARRAY[@]}"; do
            TAG_ARGS="$TAG_ARGS -t ${IMAGE}:${tag}"
          done

          # Create and push manifest using all digests
          docker buildx imagetools create $TAG_ARGS \
            $(printf '${{ needs.prepare.outputs.image }}@sha256:%s ' *)

      - name: Inspect image
        run: |
          IMAGE="${{ needs.prepare.outputs.image }}"
          TAGS="${{ needs.prepare.outputs.tags }}"
          FIRST_TAG=$(echo "$TAGS" | cut -d',' -f1)
          docker buildx imagetools inspect ${IMAGE}:${FIRST_TAG}

      - name: Summary
        run: |
          IMAGE="${{ needs.prepare.outputs.image }}"
          TAGS="${{ needs.prepare.outputs.tags }}"
          echo "## Docker Image Published 🚀" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          if [[ "${{ needs.prepare.outputs.is_release }}" == "true" ]]; then
            echo "**Type:** Release (${{ needs.prepare.outputs.release_tag }})" >> $GITHUB_STEP_SUMMARY
          else
            echo "**Type:** Commit (sha-${GITHUB_SHA:0:7})" >> $GITHUB_STEP_SUMMARY
          fi
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "**Tags:**" >> $GITHUB_STEP_SUMMARY
          echo '```' >> $GITHUB_STEP_SUMMARY
          echo "$TAGS" | tr ',' '\n' | sed "s|^|${IMAGE}:|" >> $GITHUB_STEP_SUMMARY
          echo '```' >> $GITHUB_STEP_SUMMARY
