name: Tests

on:
  push:
    branches: [ master, main, develop ]
  pull_request:
    branches: [ master, main, develop ]
  workflow_dispatch:
    inputs:
      python-version:
        description: 'Python version to test against'
        required: false
        default: '3.11'
        type: choice
        options: ['3.11', '3.12', '3.13', '3.14']
      randomly-seed:
        description: 'pytest-randomly seed (leave blank to use run ID)'
        required: false
        default: ''
      run-weekly:
        description: 'Run weekly-randomized job (3.12-3.14) instead of normal test job'
        required: false
        default: false
        type: boolean
  schedule:
    - cron: '0 6 * * 1'

jobs:
  test:
    if: github.event_name != 'schedule' && !(github.event_name == 'workflow_dispatch' && inputs.run-weekly == true)
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.11', '3.12', '3.13', '3.14']
        randomized: [false]
        include:
          - python-version: '3.11'
            randomized: true

    permissions:
      contents: read

    steps:
    - uses: actions/checkout@v6

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

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e ".[dev]"

    - name: Lint with flake8 (optional)
      run: |
        # Stop the build if there are Python syntax errors or undefined names
        python -m flake8 src/britecore_sdk --count --select=E9,F63,F7,F82 --show-source --statistics || true
        # Exit-zero treats all errors as warnings
        python -m flake8 src/britecore_sdk --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics || true
      continue-on-error: true

    - name: Run tests with pytest
      run: |
        SEED="${{ inputs.randomly-seed }}"
        RANDOM_ARGS=""
        if [ "${{ matrix.randomized }}" = "true" ] || [ -n "$SEED" ]; then
          SEED="${SEED:-${{ github.run_id }}}"
          RANDOM_ARGS="--randomly-seed=$SEED"
        fi
        pytest tests/ -v --cov=src/britecore_sdk --cov-report=term-missing --cov-report=html --cov-report=xml $RANDOM_ARGS

    - name: Type-check with mypy
      if: matrix.python-version == '3.11'
      run: |
        mypy src/britecore_sdk --ignore-missing-imports
      continue-on-error: true

    - name: Security audit with pip-audit
      if: matrix.python-version == '3.11' && matrix.randomized == false
      run: |
        pip-audit --desc on
      continue-on-error: true

    - name: Rewrite coverage paths for DeepSource
      if: matrix.python-version == '3.11' && matrix.randomized == false
      run: |
        python - <<'PY'
        import xml.etree.ElementTree as ET

        tree = ET.parse("coverage.xml")
        root = tree.getroot()

        for cls in root.findall(".//class"):
          filename = cls.attrib.get("filename", "")
          if filename and not filename.startswith("src/"):
            cls.set("filename", f"src/britecore_sdk/{filename}")

        tree.write("coverage.deepsource.xml", encoding="utf-8", xml_declaration=True)
        PY

    - name: Upload coverage to Codecov
      if: matrix.python-version == '3.11'
      uses: codecov/codecov-action@v6
      with:
        files: ./coverage.xml
        flags: unittests
        name: codecov-umbrella
        fail_ci_if_error: false

    - name: Generate coverage report
      if: matrix.python-version == '3.11' && matrix.randomized == false
      run: |
        coverage report --fail-under=84

    - name: Archive coverage report
      if: always()
      uses: actions/upload-artifact@v7
      with:
        name: coverage-report-py${{ matrix.python-version }}-randomized-${{ matrix.randomized }}
        path: htmlcov/
        overwrite: true

    - name: Report test coverage to DeepSource
      if: matrix.python-version == '3.11' && matrix.randomized == false
      uses: deepsourcelabs/test-coverage-action@master
      with:
        key: python
        coverage-file: coverage.deepsource.xml
        dsn: ${{ secrets.DEEPSOURCE_DSN }}

  weekly-randomized:
    if: github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.run-weekly == true)
    runs-on: ubuntu-latest
    strategy:
      fail-fast: false
      matrix:
        python-version: ['3.12', '3.13', '3.14']

    permissions:
      contents: read

    steps:
    - uses: actions/checkout@v6

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

    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -e ".[dev]"

    - name: Run randomized tests with pytest
      run: |
        SEED="${{ inputs.randomly-seed }}"
        SEED="${SEED:-${{ github.run_id }}}"
        pytest tests/ -v --randomly-seed=$SEED
