name: Release + Docker Images (multi-arch)

on:
  push:
    branches:
      - main
    paths:
      - 'pyproject.toml'
  workflow_dispatch:

jobs:
  check-version:
    runs-on: ubuntu-latest
    outputs:
      skip_release: ${{ steps.version.outputs.skip_release }}
      version: ${{ steps.version.outputs.version }}
      is_prerelease: ${{ steps.version.outputs.is_prerelease }}
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Extract version from pyproject.toml
        id: version
        run: |
          VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "Version: $VERSION"

          # Check if tag already exists
          if git rev-parse "v$VERSION" >/dev/null 2>&1; then
            echo "Tag v$VERSION already exists, skipping release"
            echo "skip_release=true" >> $GITHUB_OUTPUT
            exit 0
          fi
          echo "skip_release=false" >> $GITHUB_OUTPUT

          # Check if version is numeric (e.g., 0.1.16) vs prerelease (e.g., 0.1.16-rc1)
          if [[ "$VERSION" =~ ^[0-9.-]+$ ]]; then
            echo "is_prerelease=false" >> $GITHUB_OUTPUT
            echo "Release type: Production"
          else
            echo "is_prerelease=true" >> $GITHUB_OUTPUT
            echo "Release type: Prerelease"
          fi

  build:
    needs: check-version
    if: needs.check-version.outputs.skip_release != 'true'
    strategy:
      fail-fast: false
      matrix:
        include:
          # backend
          - image: backend
            file: ./Dockerfile.backend
            tag: phact/openrag-backend
            platform: linux/amd64
            arch: amd64
            runs-on: ubuntu-latest
          - image: backend
            file: ./Dockerfile.backend
            tag: phact/openrag-backend
            platform: linux/arm64
            arch: arm64
            runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-2]

          # frontend
          - image: frontend
            file: ./Dockerfile.frontend
            tag: phact/openrag-frontend
            platform: linux/amd64
            arch: amd64
            runs-on: ubuntu-latest
          - image: frontend
            file: ./Dockerfile.frontend
            tag: phact/openrag-frontend
            platform: linux/arm64
            arch: arm64
            runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-2]

          # langflow
          - image: langflow
            file: ./Dockerfile.langflow
            tag: phact/openrag-langflow
            platform: linux/amd64
            arch: amd64
            runs-on: ubuntu-latest
          - image: langflow
            file: ./Dockerfile.langflow
            tag: phact/openrag-langflow
            platform: linux/arm64
            arch: arm64
            runs-on: self-hosted

          # opensearch
          - image: opensearch
            file: ./Dockerfile
            tag: phact/openrag-opensearch
            platform: linux/amd64
            arch: amd64
            runs-on: ubuntu-latest
          - image: opensearch
            file: ./Dockerfile
            tag: phact/openrag-opensearch
            platform: linux/arm64
            arch: arm64
            runs-on: [self-hosted, linux, ARM64, langflow-ai-arm64-2]

    runs-on: ${{ matrix.runs-on }}

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

      - name: Extract version from pyproject.toml
        id: version
        run: |
          VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "Version: $VERSION"

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

      - name: Login to Docker Hub
        if: github.event_name != 'pull_request'
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Build and push ${{ matrix.image }} (${{ matrix.arch }})
        uses: docker/build-push-action@v5
        with:
          context: .
          file: ${{ matrix.file }}
          platforms: ${{ matrix.platform }}
          push: ${{ github.event_name != 'pull_request' }}
          tags: ${{ matrix.tag }}:${{ steps.version.outputs.version }}-${{ matrix.arch }}
          cache-from: type=gha,scope=${{ matrix.image }}-${{ matrix.arch }}
          cache-to: type=gha,mode=max,scope=${{ matrix.image }}-${{ matrix.arch }}

  manifest:
    needs: [build, check-version]
    runs-on: ubuntu-latest
    if: github.event_name != 'pull_request' && needs.check-version.outputs.skip_release != 'true'
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Extract version from pyproject.toml
        id: version
        run: |
          VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
          echo "version=$VERSION" >> $GITHUB_OUTPUT

      - name: Login to Docker Hub
        uses: docker/login-action@v3
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Create and push multi-arch manifests
        run: |
          VERSION=${{ steps.version.outputs.version }}

          # Create versioned tags
          docker buildx imagetools create -t phact/openrag-backend:$VERSION \
            phact/openrag-backend:$VERSION-amd64 \
            phact/openrag-backend:$VERSION-arm64

          docker buildx imagetools create -t phact/openrag-frontend:$VERSION \
            phact/openrag-frontend:$VERSION-amd64 \
            phact/openrag-frontend:$VERSION-arm64

          docker buildx imagetools create -t phact/openrag-langflow:$VERSION \
            phact/openrag-langflow:$VERSION-amd64 \
            phact/openrag-langflow:$VERSION-arm64

          docker buildx imagetools create -t phact/openrag-opensearch:$VERSION \
            phact/openrag-opensearch:$VERSION-amd64 \
            phact/openrag-opensearch:$VERSION-arm64

          # Only update latest tags if version is numeric
          if [[ "$VERSION" =~ ^[0-9.-]+$ ]]; then
            echo "Updating latest tags for production release: $VERSION"
            docker buildx imagetools create -t phact/openrag-backend:latest \
              phact/openrag-backend:$VERSION-amd64 \
              phact/openrag-backend:$VERSION-arm64

            docker buildx imagetools create -t phact/openrag-frontend:latest \
              phact/openrag-frontend:$VERSION-amd64 \
              phact/openrag-frontend:$VERSION-arm64

            docker buildx imagetools create -t phact/openrag-langflow:latest \
              phact/openrag-langflow:$VERSION-amd64 \
              phact/openrag-langflow:$VERSION-arm64

            docker buildx imagetools create -t phact/openrag-opensearch:latest \
              phact/openrag-opensearch:$VERSION-amd64 \
              phact/openrag-opensearch:$VERSION-arm64
          else
            echo "Skipping latest tags - version: $VERSION (not numeric)"
          fi

  build-python-packages:
    needs: [manifest, check-version]
    runs-on: ubuntu-latest
    if: needs.check-version.outputs.skip_release != 'true'
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.13'

      - name: Install uv
        uses: astral-sh/setup-uv@v3

      - name: Extract version from pyproject.toml
        id: version
        run: |
          VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2)
          echo "version=$VERSION" >> $GITHUB_OUTPUT
          echo "Version: $VERSION"

      - name: Build wheel and source distribution
        run: |
          uv build

      - name: List built artifacts
        run: |
          ls -la dist/
          echo "Built artifacts:"
          for file in dist/*; do
            echo "  - $(basename $file) ($(stat -c%s $file | numfmt --to=iec-i)B)"
          done

      - name: Upload build artifacts
        uses: actions/upload-artifact@v4
        with:
          name: python-packages
          path: dist/
          retention-days: 30

      - name: Create Release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: v${{ steps.version.outputs.version }}
          name: Release ${{ steps.version.outputs.version }}
          draft: false
          prerelease: ${{ needs.check-version.outputs.is_prerelease }}
          generate_release_notes: true
          files: |
            dist/*.whl
            dist/*.tar.gz
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

      - name: Publish to PyPI
        run: |
          uv publish
        env:
          UV_PUBLISH_TOKEN: ${{ secrets.UV_PUBLISH_TOKEN }}
