name: edgequake-litellm CI

on:
  push:
    branches: [ main, "feat/litellm", "feat/*" ]
    paths:
      - "edgequake-litellm/**"
      - "src/**"
      - "Cargo.toml"
      - "Cargo.lock"
      - ".github/workflows/python-ci.yml"
  pull_request:
    branches: [ main ]
    paths:
      - "edgequake-litellm/**"
      - "src/**"
      - "Cargo.toml"
      - "Cargo.lock"
      - ".github/workflows/python-ci.yml"

env:
  CARGO_TERM_COLOR: always
  RUST_BACKTRACE: 1

# Cancel in-progress runs on the same branch/PR to save CI minutes
concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

jobs:
  # ─── 0. Version consistency ─────────────────────────────────────────────────
  version-check:
    name: Version consistency
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Verify pyproject.toml and Cargo.toml versions match
        shell: bash
        run: |
          PY_VER=$(grep '^version' edgequake-litellm/pyproject.toml | head -1 | cut -d'"' -f2)
          RS_VER=$(grep '^version' edgequake-litellm/Cargo.toml | head -1 | cut -d'"' -f2)
          echo "pyproject.toml : $PY_VER"
          echo "Cargo.toml     : $RS_VER"
          if [ "$PY_VER" != "$RS_VER" ]; then
            echo "::error::Version mismatch — pyproject.toml ($PY_VER) != Cargo.toml ($RS_VER)"
            exit 1
          fi

  # ─── 1. Rust clippy for the Python bindings crate ──────────────────────────
  clippy:
    name: Clippy (edgequake-litellm)
    runs-on: ubuntu-latest
    needs: version-check
    steps:
      - uses: actions/checkout@v4

      - name: Install stable Rust + clippy
        uses: dtolnay/rust-toolchain@stable
        with:
          components: clippy

      - name: Cache Cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-python-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-python-

      - name: Install maturin
        run: pip install maturin

      - name: Clippy
        working-directory: edgequake-litellm
        run: cargo clippy --all-features -- -D warnings

  # ─── 2. Lint Python (ruff) ───────────────────────────────────────────────
  lint:
    name: Ruff lint
    runs-on: ubuntu-latest
    needs: version-check
    steps:
      - uses: actions/checkout@v4

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

      - name: Install ruff
        run: pip install "ruff>=0.3"

      - name: Run ruff check
        working-directory: edgequake-litellm
        run: ruff check python/

  # ─── 3. Type check (mypy) ───────────────────────────────────────────────────
  typecheck:
    name: Mypy type check
    runs-on: ubuntu-latest
    needs: [clippy, lint]
    steps:
      - uses: actions/checkout@v4

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

      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-typecheck-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-typecheck-

      - name: Install Python dependencies
        working-directory: edgequake-litellm
        run: pip install "mypy>=1.8" "pytest>=8.0" "pytest-asyncio>=0.24"

      - name: Build & install (maturin PEP-517)
        working-directory: edgequake-litellm
        run: pip install . -v

      - name: Run mypy
        working-directory: edgequake-litellm
        run: mypy python/edgequake_litellm --ignore-missing-imports

  # ─── 4. Build wheels and run unit tests ─────────────────────────────────────
  test:
    name: Test (${{ matrix.os }} / Python ${{ matrix.python-version }})
    needs: [clippy, lint]
    strategy:
      fail-fast: false
      matrix:
        include:
          # ── Linux x86_64 ────────────────────────────────────────────────────
          - os: ubuntu-latest
            python-version: "3.9"
          - os: ubuntu-latest
            python-version: "3.11"
          - os: ubuntu-latest
            python-version: "3.13"

          # ── macOS Apple Silicon (ARM64) — macos-latest is arm64 ──────────
          - os: macos-latest
            python-version: "3.11"
          - os: macos-latest
            python-version: "3.13"

          # ── macOS Intel (x86_64) ────────────────────────────────────────
          - os: macos-13
            python-version: "3.11"
            can-fail: true  # macos-13 pool may have limited availability

          # ── Windows x86_64 ──────────────────────────────────────────────
          - os: windows-latest
            python-version: "3.11"
          - os: windows-latest
            python-version: "3.13"

    runs-on: ${{ matrix.os }}
    continue-on-error: ${{ matrix.can-fail == true }}

    steps:
      - uses: actions/checkout@v4

      - name: Set up Python ${{ matrix.python-version }}
        uses: actions/setup-python@v5
        with:
          python-version: ${{ matrix.python-version }}

      - name: Install stable Rust
        uses: dtolnay/rust-toolchain@stable

      - name: Cache Cargo
        uses: actions/cache@v4
        with:
          path: |
            ~/.cargo/registry
            ~/.cargo/git
            target
          key: ${{ runner.os }}-cargo-${{ matrix.python-version }}-${{ hashFiles('**/Cargo.lock') }}
          restore-keys: ${{ runner.os }}-cargo-${{ matrix.python-version }}-

      - name: Install Python dev dependencies
        working-directory: edgequake-litellm
        run: pip install "pytest>=8.0" "pytest-asyncio>=0.24"

      - name: Build & install edgequake-litellm (PEP-517)
        working-directory: edgequake-litellm
        run: pip install . -v

      - name: Run unit tests (no API keys required)
        working-directory: edgequake-litellm
        run: pytest tests/ -v -k "not e2e" --tb=short

  # ─── 5. Linux ARM64 cross-compile check ────────────────────────────────────
  build-linux-arm64:
    name: Build wheel (Linux aarch64)
    runs-on: ubuntu-latest
    needs: [clippy, lint]
    continue-on-error: true  # cross-compilation of ring crate may be flaky
    steps:
      - uses: actions/checkout@v4

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

      - name: Build ARM64 manylinux wheel (cross-compile via QEMU)
        uses: PyO3/maturin-action@v1
        with:
          working-directory: edgequake-litellm
          target: aarch64
          manylinux: auto
          args: --release --out dist
          sccache: "true"
        env:
          # ring crate: -D__ARM_ARCH=8 required for old GCC in manylinux2014 container
          CFLAGS_aarch64_unknown_linux_gnu: "-march=armv8-a -D__ARM_ARCH=8"

      - name: Verify wheel was created
        shell: bash
        run: ls -la edgequake-litellm/dist/*.whl

  # ─── 6. README sanity check ────────────────────────────────────────────────
  docs:
    name: README sanity
    runs-on: ubuntu-latest
    needs: version-check
    steps:
      - uses: actions/checkout@v4

      - name: Check README contains expected content
        run: |
          python3 -c "
          import pathlib
          text = pathlib.Path('edgequake-litellm/README.md').read_text()
          assert 'edgequake-litellm' in text, 'README missing package name'
          assert 'litellm' in text.lower(), 'README missing litellm reference'
          print('README OK')
          "
