name: Release

concurrency:
  group: release-main
  cancel-in-progress: false

on:
  workflow_dispatch:
    inputs:
      version_bump:
        description: "Version bump type"
        type: choice
        options:
          - patch
          - minor
          - major
        default: patch
        required: true

jobs:
  bump:
    name: Bump version, tag, and create release
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    outputs:
      new_version: ${{ steps.compute.outputs.new_version }}
      tag: ${{ steps.tag.outputs.tag }}
      bump_branch: ${{ steps.bump_branch.outputs.name }}
    steps:
      - name: Ensure workflow is running on main
        shell: bash
        run: |
          set -euo pipefail
          if [[ "${GITHUB_REF_NAME}" != "main" ]]; then
            echo "This workflow must be run on the main branch. Current ref: ${GITHUB_REF_NAME}" >&2
            exit 1
          fi

      - name: Checkout repository
        uses: actions/checkout@v6
        with:
          ref: main
          fetch-depth: 0

      - name: Compute new version
        id: compute
        shell: bash
        run: |
          set -euo pipefail
          BUMP="${{ inputs.version_bump }}"
          CURRENT_VERSION=$(jq -r '.version' "MCPForUnity/package.json")
          echo "Current version: $CURRENT_VERSION"

          IFS='.' read -r MA MI PA <<< "$CURRENT_VERSION"
          case "$BUMP" in
            major)
              ((MA+=1)); MI=0; PA=0
              ;;
            minor)
              ((MI+=1)); PA=0
              ;;
            patch)
              ((PA+=1))
              ;;
            *)
              echo "Unknown version_bump: $BUMP" >&2
              exit 1
              ;;
          esac

          NEW_VERSION="$MA.$MI.$PA"
          echo "New version: $NEW_VERSION"
          echo "new_version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
          echo "current_version=$CURRENT_VERSION" >> "$GITHUB_OUTPUT"

      - name: Compute tag
        id: tag
        env:
          NEW_VERSION: ${{ steps.compute.outputs.new_version }}
        shell: bash
        run: |
          set -euo pipefail
          echo "tag=v${NEW_VERSION}" >> "$GITHUB_OUTPUT"

      - name: Update files to new version
        env:
          NEW_VERSION: ${{ steps.compute.outputs.new_version }}
        shell: bash
        run: |
          set -euo pipefail

          echo "Updating all version references to $NEW_VERSION"
          python3 tools/update_versions.py --version "$NEW_VERSION"

      - name: Commit version bump to a temporary branch
        id: bump_branch
        env:
          NEW_VERSION: ${{ steps.compute.outputs.new_version }}
        shell: bash
        run: |
          set -euo pipefail
          BRANCH="release/v${NEW_VERSION}"
          echo "name=$BRANCH" >> "$GITHUB_OUTPUT"

          git config user.name "GitHub Actions"
          git config user.email "actions@github.com"
          git checkout -b "$BRANCH"
          git add MCPForUnity/package.json manifest.json "Server/pyproject.toml" Server/README.md
          if git diff --cached --quiet; then
            echo "No version changes to commit."
          else
            git commit -m "chore: bump version to ${NEW_VERSION}"
          fi

          echo "Pushing bump branch $BRANCH"
          git push origin "$BRANCH"

      - name: Create PR for version bump into main
        id: bump_pr
        env:
          GH_TOKEN: ${{ github.token }}
          NEW_VERSION: ${{ steps.compute.outputs.new_version }}
          BRANCH: ${{ steps.bump_branch.outputs.name }}
        shell: bash
        run: |
          set -euo pipefail
          PR_URL=$(gh pr create \
            --base main \
            --head "$BRANCH" \
            --title "chore: bump version to ${NEW_VERSION}" \
            --body "Automated version bump to ${NEW_VERSION}.")
          echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT"
          PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
          echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"

      - name: Enable auto-merge and merge PR
        env:
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ steps.bump_pr.outputs.pr_number }}
        shell: bash
        run: |
          set -euo pipefail
          # Enable auto-merge (requires repo setting "Allow auto-merge")
          gh pr merge "$PR_NUMBER" --merge --auto || true
          # Wait for PR to be merged (poll up to 2 minutes)
          for i in {1..24}; do
            STATE=$(gh pr view "$PR_NUMBER" --json state -q '.state')
            if [[ "$STATE" == "MERGED" ]]; then
              echo "PR merged successfully."
              exit 0
            fi
            echo "Waiting for PR to merge... (state: $STATE)"
            sleep 5
          done
          echo "PR did not merge in time. Attempting direct merge..."
          gh pr merge "$PR_NUMBER" --merge

      - name: Fetch merged main and create tag
        env:
          TAG: ${{ steps.tag.outputs.tag }}
        shell: bash
        run: |
          set -euo pipefail
          git fetch origin main
          git checkout main
          git pull origin main

          echo "Preparing to create tag $TAG"

          if git ls-remote --tags origin | grep -q "refs/tags/$TAG$"; then
            echo "Tag $TAG already exists on remote. Refusing to release." >&2
            exit 1
          fi

          git tag -a "$TAG" -m "Version ${TAG#v}"
          git push origin "$TAG"

      - name: Clean up release branch
        if: always()
        env:
          GH_TOKEN: ${{ github.token }}
          BRANCH: ${{ steps.bump_branch.outputs.name }}
        shell: bash
        run: |
          set -euo pipefail
          git push origin --delete "$BRANCH" || true

      - name: Create GitHub release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ steps.tag.outputs.tag }}
          name: ${{ steps.tag.outputs.tag }}
          generate_release_notes: true

  sync_beta:
    name: Merge main back into beta via PR
    needs:
      - bump
    runs-on: ubuntu-latest
    permissions:
      contents: write
      pull-requests: write
    steps:
      - name: Checkout main
        uses: actions/checkout@v6
        with:
          ref: main
          fetch-depth: 0

      - name: Create PR to merge main into beta
        id: sync_pr
        env:
          GH_TOKEN: ${{ github.token }}
          NEW_VERSION: ${{ needs.bump.outputs.new_version }}
        shell: bash
        run: |
          set -euo pipefail
          # Check if beta is behind main
          git fetch origin beta
          if git merge-base --is-ancestor origin/main origin/beta; then
            echo "beta is already up to date with main. Skipping PR."
            echo "skipped=true" >> "$GITHUB_OUTPUT"
            exit 0
          fi

          PR_URL=$(gh pr create \
            --base beta \
            --head main \
            --title "chore: sync main (v${NEW_VERSION}) into beta" \
            --body "Automated sync of version bump from main into beta.")
          echo "pr_url=$PR_URL" >> "$GITHUB_OUTPUT"
          PR_NUMBER=$(echo "$PR_URL" | grep -oE '[0-9]+$')
          echo "pr_number=$PR_NUMBER" >> "$GITHUB_OUTPUT"
          echo "skipped=false" >> "$GITHUB_OUTPUT"

      - name: Enable auto-merge and merge sync PR
        if: steps.sync_pr.outputs.skipped != 'true'
        env:
          GH_TOKEN: ${{ github.token }}
          PR_NUMBER: ${{ steps.sync_pr.outputs.pr_number }}
        shell: bash
        run: |
          set -euo pipefail
          # Enable auto-merge (requires repo setting "Allow auto-merge")
          gh pr merge "$PR_NUMBER" --merge --auto || true
          # Wait for PR to be merged (poll up to 2 minutes)
          for i in {1..24}; do
            STATE=$(gh pr view "$PR_NUMBER" --json state -q '.state')
            if [[ "$STATE" == "MERGED" ]]; then
              echo "Sync PR merged successfully."
              exit 0
            fi
            echo "Waiting for sync PR to merge... (state: $STATE)"
            sleep 5
          done
          echo "Sync PR did not merge in time. Attempting direct merge..."
          gh pr merge "$PR_NUMBER" --merge

  publish_docker:
    name: Publish Docker image
    needs:
      - bump
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - name: Check out the repo
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.bump.outputs.tag }}
          fetch-depth: 0

      - name: Build and push Docker image
        uses: ./.github/actions/publish-docker
        with:
          docker_username: ${{ secrets.DOCKER_USERNAME }}
          docker_password: ${{ secrets.DOCKER_PASSWORD }}
          image: ${{ secrets.DOCKER_USERNAME }}/mcp-for-unity-server
          version: ${{ needs.bump.outputs.new_version }}
          include_branch_tags: "false"
          context: .
          dockerfile: Server/Dockerfile
          platforms: linux/amd64

  publish_pypi:
    name: Publish Python distribution to PyPI
    needs:
      - bump
    runs-on: ubuntu-latest
    environment:
      name: pypi
      url: https://pypi.org/p/mcpforunityserver
    permissions:
      contents: read
      id-token: write
    steps:
      - uses: actions/checkout@v6
        with:
          ref: ${{ needs.bump.outputs.tag }}
          fetch-depth: 0

      # Inlined from .github/actions/publish-pypi to avoid nested composite action issue
      # with pypa/gh-action-pypi-publish (see https://github.com/pypa/gh-action-pypi-publish/issues/338)
      - name: Install uv
        uses: astral-sh/setup-uv@v7
        with:
          version: "latest"
          enable-cache: true
          cache-dependency-glob: "Server/uv.lock"

      - name: Build a binary wheel and a source tarball
        shell: bash
        run: uv build
        working-directory: ./Server

      - name: Publish distribution to PyPI
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: Server/dist/

  publish_mcpb:
    name: Generate and publish MCPB bundle
    needs:
      - bump
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Check out the repo
        uses: actions/checkout@v6
        with:
          ref: ${{ needs.bump.outputs.tag }}
          fetch-depth: 0

      - name: Set up Node.js
        uses: actions/setup-node@v4
        with:
          node-version: "20"

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: "3.11"

      - name: Generate MCPB bundle
        env:
          NEW_VERSION: ${{ needs.bump.outputs.new_version }}
        shell: bash
        run: |
          set -euo pipefail
          python3 tools/generate_mcpb.py "$NEW_VERSION" \
            --output "unity-mcp-${NEW_VERSION}.mcpb" \
            --icon docs/images/coplay-logo.png

      - name: Upload MCPB to release
        uses: softprops/action-gh-release@v2
        with:
          tag_name: ${{ needs.bump.outputs.tag }}
          files: unity-mcp-${{ needs.bump.outputs.new_version }}.mcpb
