name: CI Python

on:
  workflow_call:

permissions:
  contents: read

jobs:
  # -------------------------------------------------------------------------
  # Lint — no Rust, no wheel build, very fast
  # -------------------------------------------------------------------------
  lint:
    name: Lint (ruff)
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - run: pip install uv
      - run: uv run --with ruff ruff check python/ tests/
      - run: uv run --with ruff ruff format --check python/ tests/

  # -------------------------------------------------------------------------
  # Type checking — needs wheel; build once with cache
  # -------------------------------------------------------------------------
  typecheck:
    name: Type checking (mypy + pyright)
    runs-on: ubuntu-latest
    env:
      RUSTFLAGS: ""  # override target-cpu=native from .cargo/config.toml
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@v2
      - run: pip install maturin numpy
      - run: maturin build --release --out dist && pip install dist/*.whl
      - run: pip install uv
      - run: uv run --with mypy --with numpy python -m mypy python/ferro_ta --ignore-missing-imports --no-error-summary
      - run: uv run --with pyright python -m pyright python/ferro_ta

  # -------------------------------------------------------------------------
  # Build wheel artifact (once per run, reused by all test matrix entries)
  # -------------------------------------------------------------------------
  build-wheel:
    name: Build wheel (ubuntu / Python ${{ matrix.python-version }})
    runs-on: ubuntu-latest
    env:
      RUSTFLAGS: ""  # override target-cpu=native from .cargo/config.toml
    strategy:
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
      - uses: dtolnay/rust-toolchain@v1
        with:
          toolchain: stable
      - uses: Swatinem/rust-cache@v2
        with:
          shared-key: "wheel-${{ matrix.python-version }}"
      - run: pip install maturin numpy
      - run: maturin build --release --out dist
      - uses: actions/upload-artifact@v7
        with:
          name: wheel-${{ matrix.python-version }}
          path: dist/*.whl

  # -------------------------------------------------------------------------
  # Test matrix — downloads pre-built wheel, no Rust compilation
  # -------------------------------------------------------------------------
  test:
    name: Test (Python ${{ matrix.python-version }})
    runs-on: ubuntu-latest
    needs: build-wheel
    strategy:
      fail-fast: false
      matrix:
        python-version: ["3.10", "3.11", "3.12", "3.13"]
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: ${{ matrix.python-version }}
      - uses: actions/download-artifact@v8
        with:
          name: wheel-${{ matrix.python-version }}
          path: dist
      - name: Install wheel + test deps
        run: |
          pip install dist/*.whl
          pip install pytest pytest-cov pandas polars hypothesis pyyaml mcp scipy
      - name: Run tests with coverage
        run: pytest tests/unit/ tests/integration/ -v --cov=ferro_ta --cov-report=xml --cov-report=term-missing --cov-fail-under=65
      - name: Check API manifest is current
        if: matrix.python-version == '3.12'
        run: python scripts/check_api_manifest.py
      - uses: actions/upload-artifact@v7
        if: matrix.python-version == '3.12'
        with:
          name: coverage-python-${{ matrix.python-version }}
          path: coverage.xml

  # -------------------------------------------------------------------------
  # Benchmark vs TA-Lib (downloads wheel from build-wheel job)
  # -------------------------------------------------------------------------
  benchmark-vs-talib:
    name: Benchmark vs TA-Lib
    runs-on: ubuntu-latest
    needs: build-wheel
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - uses: actions/download-artifact@v8
        with:
          name: wheel-3.12
          path: dist
      - name: Install TA-Lib C library
        run: |
          sudo apt-get update
          sudo apt-get install -y build-essential curl
          curl -sL https://sourceforge.net/projects/ta-lib/files/ta-lib/0.4.0/ta-lib-0.4.0-src.tar.gz/download -o ta-lib-0.4.0-src.tar.gz
          tar -xzf ta-lib-0.4.0-src.tar.gz
          cd ta-lib && ./configure --prefix=/usr && make && sudo make install && sudo ldconfig
      - run: pip install dist/*.whl numpy ta-lib
      - run: python benchmarks/bench_vs_talib.py --sizes 10000 100000 --json benchmark_vs_talib.json
      - run: python3 benchmarks/check_vs_talib_regression.py --input benchmark_vs_talib.json
      - uses: actions/upload-artifact@v7
        with:
          name: benchmark-vs-talib
          path: benchmark_vs_talib.json

  # -------------------------------------------------------------------------
  # Performance smoke (downloads wheel from build-wheel job)
  # -------------------------------------------------------------------------
  perf-smoke:
    name: Performance smoke and contracts
    runs-on: ubuntu-latest
    needs: build-wheel
    steps:
      - uses: actions/checkout@v6
      - uses: actions/setup-python@v6
        with:
          python-version: "3.12"
      - uses: actions/download-artifact@v8
        with:
          name: wheel-3.12
          path: dist
      - run: pip install dist/*.whl numpy pytest
      - run: |
          python benchmarks/run_perf_contract.py \
            --output-dir perf-contract \
            --skip-talib \
            --skip-simd \
            --batch-samples 20000 \
            --batch-series 32 \
            --streaming-bars 20000 \
            --price-bars 20000 \
            --iv-bars 50000
      - run: python benchmarks/check_hotspot_regression.py --input perf-contract/runtime_hotspots.json
      - uses: actions/upload-artifact@v7
        with:
          name: perf-contract
          path: perf-contract/
