name: Publish to (Test)PyPI on tag

on:
  push:
    tags:
      - 'v*'   # fire on tag pushes like v0.3.5, v0.3.5rc1
  create:      # also fire when a tag is created
  workflow_dispatch:
    inputs:
      tag:
        description: 'Tag to build/publish (e.g., v0.3.5 or v0.3.5rc1)'
        required: true

permissions:
  contents: read

jobs:
  build:
    # Run only for tags named v* across push/create/dispatch
    if: >
      (github.event_name == 'push'   && startsWith(github.ref, 'refs/tags/v')) ||
      (github.event_name == 'create' && github.ref_type == 'tag' && startsWith(github.ref, 'v')) ||
      (github.event_name == 'workflow_dispatch' && startsWith(inputs.tag, 'v'))
    name: Build sdist & wheel
    runs-on: ubuntu-latest
    permissions:
      contents: read
    steps:
      - uses: actions/checkout@v6
        with:
          # On manual dispatch, check out the requested tag; otherwise use the event ref
          ref: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref }}

      - uses: actions/setup-python@v6
        with:
          python-version: '3.11'

      - name: Install build tooling
        run: |
          python -m pip install --upgrade pip
          python -m pip install build twine pkginfo

      - name: Clean previous artifacts
        run: rm -rf dist

      - name: Build
        run: python -m build

      - name: Verify metadata
        run: twine check dist/*

      - name: Ensure tag matches package version (guardrail)
        run: |
          # Determine the tag name across all trigger types
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            TAG_RAW="${{ inputs.tag }}"
          elif [ -n "${GITHUB_REF_NAME}" ]; then
            TAG_RAW="${GITHUB_REF_NAME}"
          else
            TAG_RAW="${GITHUB_REF##refs/tags/}"
          fi
          TAG="${TAG_RAW#v}"   # strip leading 'v'
          echo "TAG=${TAG}"

          # Read version from the first wheel's METADATA (no filename parsing)
          PKG_VER=$(python -c "import glob, pkginfo; w=sorted(glob.glob('dist/*.whl'))[0]; print(pkginfo.Wheel(w).version)")
          echo "PKG_VER=${PKG_VER}"

          if [[ "${PKG_VER}" != "${TAG}" && "${PKG_VER}" != ${TAG}* ]]; then
            echo "Tag (v${TAG}) does not match package version (${PKG_VER})"
            exit 1
          fi

      - name: Upload build artifacts
        uses: actions/upload-artifact@v5
        with:
          name: dist
          path: dist/*

  publish:
    # Same gating as build
    if: >
      (github.event_name == 'push'   && startsWith(github.ref, 'refs/tags/v')) ||
      (github.event_name == 'create' && github.ref_type == 'tag' && startsWith(github.ref, 'v')) ||
      (github.event_name == 'workflow_dispatch' && startsWith(inputs.tag, 'v'))
    name: Publish to (Test)PyPI
    needs: build
    runs-on: ubuntu-latest
    permissions:
      id-token: write   # required for PyPI Trusted Publishing (OIDC)
      contents: read
    steps:
      - uses: actions/download-artifact@v6
        with:
          name: dist
          path: dist

      - name: Choose index based on tag (rc/a/b -> TestPyPI)
        id: idx
        run: |
          # Determine the tag name across all trigger types
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            TAG="${{ inputs.tag }}"
          elif [ -n "${GITHUB_REF_NAME}" ]; then
            TAG="${GITHUB_REF_NAME}"
          else
            TAG="${GITHUB_REF##refs/tags/}"
          fi

          if [[ "$TAG" =~ (a|b|rc) ]]; then
            echo "repo_url=https://test.pypi.org/legacy/" >> $GITHUB_OUTPUT
            echo "simple_url=https://test.pypi.org/simple" >> $GITHUB_OUTPUT
            echo "extra_url=https://pypi.org/simple" >> $GITHUB_OUTPUT
          else
            echo "repo_url=" >> $GITHUB_OUTPUT
            echo "simple_url=https://pypi.org/simple" >> $GITHUB_OUTPUT
            echo "extra_url=" >> $GITHUB_OUTPUT
          fi

      - name: Publish
        uses: pypa/gh-action-pypi-publish@release/v1
        with:
          packages-dir: dist
          repository-url: ${{ steps.idx.outputs.repo_url }}
          skip-existing: true   # safe re-runs

  verify:
    name: Verify install from published index
    needs: publish
    runs-on: ubuntu-latest
    steps:
      - uses: actions/setup-python@v6
        with:
          python-version: '3.11'

      - name: Determine version & index
        id: meta
        run: |
          if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
            TAG="${{ inputs.tag }}"
          elif [ -n "${GITHUB_REF_NAME}" ]; then
            TAG="${GITHUB_REF_NAME}"
          else
            TAG="${GITHUB_REF##refs/tags/}"
          fi
          VER="${TAG#v}"
          echo "ver=$VER" >> $GITHUB_OUTPUT
          # Propagate URLs from publish job if needed; recompute here for simplicity
          if [[ "$TAG" =~ (a|b|rc) ]]; then
            echo "simple_url=https://test.pypi.org/simple" >> $GITHUB_OUTPUT
            echo "extra_url=https://pypi.org/simple" >> $GITHUB_OUTPUT
          else
            echo "simple_url=https://pypi.org/simple" >> $GITHUB_OUTPUT
            echo "extra_url=" >> $GITHUB_OUTPUT
          fi

      - name: Install just-published version
        run: |
          python -m pip install -U pip
          if [ -n "${{ steps.meta.outputs.extra_url }}" ]; then
            python -m pip install --no-cache-dir \
              --index-url "${{ steps.meta.outputs.simple_url }}" \
              --extra-index-url "${{ steps.meta.outputs.extra_url }}" \
              "openavmkit==${{ steps.meta.outputs.ver }}"
          else
            python -m pip install --no-cache-dir \
              --index-url "${{ steps.meta.outputs.simple_url }}" \
              "openavmkit==${{ steps.meta.outputs.ver }}"
          fi

      - name: Import check
        run: |
          python -c "import importlib.metadata as m, openavmkit; \
          print('installed:', m.version('openavmkit')); \
          print('__version__:', getattr(openavmkit, '__version__', '<none>'))"