# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License.  You may obtain a copy of the License at
#
#   http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied.  See the License for the
# specific language governing permissions and limitations
# under the License.

name: Publish Python 🐍 distribution 📦 to PyPI

on:
  workflow_call:
    inputs:
      release_tag:
        description: 'Release tag (e.g., v0.4.0 or v0.4.0-rc.1)'
        required: true
        type: string
  workflow_dispatch:
    inputs:
      release_tag:
        description: 'Release tag (e.g., v0.4.0 or v0.4.0-rc.1)'
        required: true
        type: string

permissions:
  contents: read

jobs:
  validate-release-tag:
    runs-on: ubuntu-latest
    outputs:
      cargo-version: ${{ steps.validate.outputs.cargo-version }}
      is-rc: ${{ steps.validate.outputs.is-rc }}
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        if: ${{ github.event_name == 'workflow_dispatch' }}
        with:
          persist-credentials: false

      - name: Validate release tag format
        id: validate
        # Valid formats: v<major>.<minor>.<patch> OR v<major>.<minor>.<patch>-rc.<release_candidate>
        shell: bash
        env:
          RELEASE_TAG: ${{ inputs.release_tag }}
        run: |
          echo "Validating release tag: $RELEASE_TAG"
          if [[ ! "$RELEASE_TAG" =~ ^v[0-9]+\.[0-9]+\.[0-9]+(-rc\.[0-9]+)?$ ]]; then
            echo "❌ Invalid release tag format: $RELEASE_TAG"
            echo "Expected format: v<major>.<minor>.<patch> OR v<major>.<minor>.<patch>-rc.<release_candidate>"
            echo "Examples: v0.4.0, v1.2.3-rc.1"
            exit 1
          fi
          echo "✅ Release tag format is valid: $RELEASE_TAG"
          
          # Strip 'v' prefix for cargo version
          CARGO_VERSION="${RELEASE_TAG#v}"
          echo "Cargo version (without v prefix): $CARGO_VERSION"
          
          # For manual triggers, validate that the tag matches the version in Cargo.toml
          if [ "${{ github.event_name }}" == "workflow_dispatch" ]; then
            # Extract base version (without -rc.X suffix) for comparison with Cargo.toml
            BASE_VERSION="${CARGO_VERSION%-rc.*}"
            echo "Base version (for Cargo.toml comparison): $BASE_VERSION"
            
            # Read version from Cargo.toml and validate it matches
            CARGO_TOML_VERSION=$(grep '^version = ' bindings/python/Cargo.toml | head -1 | sed 's/version = "\(.*\)"/\1/')
            echo "Version in bindings/python/Cargo.toml: $CARGO_TOML_VERSION"
            
            if [ "$BASE_VERSION" != "$CARGO_TOML_VERSION" ]; then
              echo "❌ Version mismatch!"
              echo "   Release tag base version: $BASE_VERSION"
              echo "   bindings/python/Cargo.toml version: $CARGO_TOML_VERSION"
              echo "Please ensure the release tag matches the version in Cargo.toml"
              exit 1
            fi
            echo "✅ Version matches bindings/python/Cargo.toml"
          fi
          
          # Check if this is a release candidate
          if [[ "$RELEASE_TAG" =~ -rc\.[0-9]+$ ]]; then
            IS_RC="true"
            echo "This is a release candidate"
          else
            IS_RC="false"
            echo "This is a stable release"
          fi
          
          # Set outputs for other jobs to use
          echo "cargo-version=$CARGO_VERSION" >> $GITHUB_OUTPUT
          echo "is-rc=$IS_RC" >> $GITHUB_OUTPUT

  sdist:
    runs-on: ubuntu-latest
    needs: [validate-release-tag]
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          persist-credentials: false

      - name: Install toml-cli
        if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
        run: cargo install toml-cli
      
      - name: Set cargo version for RC
        if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
        working-directory: "bindings/python"
        run: |
          echo "Setting cargo version to: ${NEEDS_VALIDATE_RELEASE_TAG_OUTPUTS_CARGO_VERSION}"
          toml set Cargo.toml package.version "${NEEDS_VALIDATE_RELEASE_TAG_OUTPUTS_CARGO_VERSION}" > Cargo.toml.tmp
          # doing this explicitly to avoid issue in Windows where `mv` does not overwrite existing file
          rm Cargo.toml
          mv Cargo.toml.tmp Cargo.toml
        shell: bash
        env:
          NEEDS_VALIDATE_RELEASE_TAG_OUTPUTS_CARGO_VERSION: ${{ needs.validate-release-tag.outputs.cargo-version }}

      - uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          working-directory: "bindings/python"
          command: sdist
          args: -o dist
      - name: Upload sdist
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-sdist
          path: bindings/python/dist

  wheels:
    runs-on: "${{ matrix.os }}"
    needs: [validate-release-tag]
    strategy:
      max-parallel: 15
      matrix:
        include:
          - { os: windows-latest }
          - { os: macos-latest, target: "universal2-apple-darwin" }
          - { os: ubuntu-latest, target: "x86_64" }
          - {
              os: ubuntu-latest,
              target: "aarch64",
              manylinux: "manylinux_2_28",
            }
          - { os: ubuntu-latest, target: "armv7l" }
    steps:
      - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6
        with:
          persist-credentials: false

      - name: Install toml-cli
        if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
        run: cargo install toml-cli
      
      - name: Set cargo version for RC
        if: ${{ needs.validate-release-tag.outputs.is-rc == 'true' }}
        working-directory: "bindings/python"
        shell: bash
        env:
          CARGO_VERSION: ${{ needs.validate-release-tag.outputs.cargo-version }}
        run: |
          echo "Setting cargo version to: $CARGO_VERSION"
          toml set Cargo.toml package.version "$CARGO_VERSION" > Cargo.toml.tmp
          # doing this explicitly to avoid issue in Windows where `mv` does not overwrite existing file
          rm Cargo.toml
          mv Cargo.toml.tmp Cargo.toml

      - uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6
        with:
          python-version: 3.12
      - name: Get MSRV
        id: get-msrv
        uses: ./.github/actions/get-msrv

      - name: Setup Rust toolchain
        uses: ./.github/actions/setup-builder
        with:
          rust-version: ${{ steps.get-msrv.outputs.msrv }}
      - uses: PyO3/maturin-action@04ac600d27cdf7a9a280dadf7147097c42b757ad # v1.50.1
        with:
          target: ${{ matrix.target }}
          manylinux: ${{ matrix.manylinux || 'auto' }}
          working-directory: "bindings/python"
          command: build
          args: --release -o dist -i python3.12 # Explicitly set interpreter; manylinux containers have multiple Pythons and maturin may pick an older one
      - name: Upload wheels
        uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7.0.0
        with:
          name: wheels-${{ matrix.os }}-${{ matrix.target }}
          path: bindings/python/dist

  pypi-publish:
    name: Publish Python 🐍 distribution 📦 to Pypi
    needs: [sdist, wheels]
    runs-on: ubuntu-latest

    environment:
      name: pypi
      url: https://pypi.org/p/pyiceberg-core

    permissions:
      id-token: write # IMPORTANT: mandatory for trusted publishing

    steps:
      - name: Download all the dists
        uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8
        with:
          pattern: wheels-*
          merge-multiple: true
          path: bindings/python/dist
      - name: Publish to PyPI
        uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0
        with:
          skip-existing: true
          packages-dir: bindings/python/dist
          verbose: true
