# packages/sdk/python — Python SDK tasks.
#
# The underlying tooling is `uv` + `maturin`. Callers should go through these
# recipes so the commands are discoverable and consistent.

import "../../../justfiles/common.just"

# `source_directory()` (not `justfile_directory()`) because this file is
# imported as a `mod` from `packages/sdk/justfile` via `justfile` (root).
# `justfile_directory()` always resolves to the *root* justfile's directory
# regardless of module depth, which would point `_pkg` / `_spec` / `_generated`
# at the repo root instead of `packages/sdk/python/`.
_pkg := source_directory()
_spec := source_directory() / ".." / ".." / "api-spec" / "openapi.json"
_generated := source_directory() / "python" / "openapp_sdk" / "models" / "_generated.py"
_compose := source_directory() / ".." / "docker" / "compose.yaml"

_:
    @just --list

# Install/refresh the dev virtualenv at `.venv` using `uv` (optional host workflows:
# lint-fix, reporting recipes below).
_venv:
    cd {{ _pkg }} && uv sync --all-extras

# Run uv after sync inside sdk-python (same service as `just sdk docker python`).
_py *ARGS:
    SDK_DOCKER_UID="${SDK_DOCKER_UID:-$(id -u)}" SDK_DOCKER_GID="${SDK_DOCKER_GID:-$(id -g)}" docker compose -f {{ _compose }} run --rm sdk-python \
        sh -euxc 'uv sync --all-extras && {{ ARGS }}'

# Sync + maturin develop, then ARGS (tests need the PyO3 bridge built).
_py_bridge *ARGS:
    SDK_DOCKER_UID="${SDK_DOCKER_UID:-$(id -u)}" SDK_DOCKER_GID="${SDK_DOCKER_GID:-$(id -g)}" docker compose -f {{ _compose }} run --rm sdk-python \
        sh -euxc 'uv sync --all-extras && uv run maturin develop --features pyo3/extension-module && {{ ARGS }}'

# Shell snippet after `uv sync` when ARGS cannot be expressed as a single `just` argv list (e.g. `&&` chains).
_py_cmd CMD:
    SDK_DOCKER_UID="${SDK_DOCKER_UID:-$(id -u)}" SDK_DOCKER_GID="${SDK_DOCKER_GID:-$(id -g)}" docker compose -f {{ _compose }} run --rm sdk-python \
        sh -euxc 'uv sync --all-extras && {{ CMD }}'

# `docker compose run sdk-python <argv>` without the default `sh -euxc` wrapper (e.g. `bash script.sh`).
_py_raw *ARGS:
    SDK_DOCKER_UID="${SDK_DOCKER_UID:-$(id -u)}" SDK_DOCKER_GID="${SDK_DOCKER_GID:-$(id -g)}" docker compose -f {{ _compose }} run --rm sdk-python {{ ARGS }}

# Fast iteration: `maturin develop` builds the bridge in-place (debug mode).
build-develop:
    @just _py uv run maturin develop --features pyo3/extension-module

# Canonical SDK recipe name (`MULTI_SDK_ROADMAP.md`); same as `build-develop`.
build: build-develop

# Release wheel for the local platform (CI uses `maturin-action` to cross-build).
wheel: _venv
    cd {{ _pkg }} && uv run maturin build --release --strip

# sdist for PyPI (includes the Rust source so manual builds are possible).
sdist: _venv
    cd {{ _pkg }} && uv run maturin sdist

# Run the full test suite (unit + integration; integration tests auto-skip without
# `OPENAPP_SDK_TEST_API_KEY`).
test:
    @just _py_bridge uv run pytest -v

# Run just the unit suite — fast, no backend needed.
test-unit:
    @just _py_bridge uv run pytest -v tests/unit

# Consumer contract tests (Pact; no live backend).
test-contract:
    @just _py_bridge uv run pytest -v tests/contract

# Shared Gherkin scenarios under `packages/sdk/features` (skip `@wip` placeholders).
behave: _venv
    cd {{ _pkg }} && uv run behave ../features --tags=-wip

# Behave with JUnit + Allure raw results (same layout as CI `gherkin-behave`).
behave-reports: _venv
    #!/usr/bin/env bash
    set -euo pipefail
    rep="{{ _pkg }}/.tmp/sdk-reports"
    mkdir -p "$rep/behave-junit" "$rep/allure-behave-results"
    cd "{{ _pkg }}"
    uv run behave ../features --tags=-wip --no-color \
      -f allure_behave.formatter:AllureFormatter -o "$rep/allure-behave-results" \
      -f plain --junit --junit-directory="$rep/behave-junit"

# Unit tests with JUnit XML + Allure raw results under `.tmp/sdk-reports/` (gitignored).
test-reports: _venv
    #!/usr/bin/env bash
    set -euo pipefail
    rep="{{ _pkg }}/.tmp/sdk-reports"
    mkdir -p "$rep"
    cd "{{ _pkg }}"
    uv run pytest -v tests/unit \
      --junitxml="$rep/pytest-junit.xml" \
      --alluredir="$rep/allure-results"

# Generate HTML and open Allure (requires `allure` on PATH; see packages/sdk/docs/REPORTING.md).
report-allure-open: test-reports
    #!/usr/bin/env bash
    set -euo pipefail
    rep="{{ _pkg }}/.tmp/sdk-reports"
    if ! command -v allure >/dev/null 2>&1; then
      echo "allure: command not found. Install Allure commandline:" >&2
      echo "  https://docs.qameta.io/allure/#_installing_a_commandline" >&2
      exit 1
    fi
    allure generate "$rep/allure-results" -o "$rep/allure-report" --clean
    allure open "$rep/allure-report"

# Ruff + mypy.
lint:
    @just _py_cmd "uv run ruff check . && uv run ruff format --check . && uv run python -m mypy"

lint-fix: _venv
    cd {{ _pkg }} && uv run ruff format .
    cd {{ _pkg }} && uv run ruff check --fix .

# Canonical SDK recipe name (`MULTI_SDK_ROADMAP.md`); same as `openapi-gen`.
generate: openapi-gen

# Regenerate the committed Pydantic models from the OpenAPI spec.
openapi-gen:
    @just _py bash scripts/openapi_models.sh gen

# README "Prebuilt wheels" bullets must match openapp-sdk-release.yml (CI guard).
readme-wheel-check:
    @just _py uv run python scripts/check_wheel_readme_drift.py

# Drift check for the committed Pydantic models.
openapi-check:
    @just _py bash scripts/openapi_models.sh check

# Same pytest/Behave/report layout as `.github/workflows/openapp-sdk-release.yml` (JUnit + Allure raw under `.tmp/sdk-reports/`).
release-gate:
    bash scripts/release_gate.sh

# Composite recipe used by `scripts/pre-commit-subproject-wrapper.sh packages/sdk/python`.
pre-commit:
    @just _py_raw bash /workspace/packages/sdk/python/scripts/run_pre_commit.sh

gherkin-tier0-check:
    @just _py uv run python scripts/check_gherkin_tier0.py

gherkin-story-pack-check:
    @just _py uv run python scripts/check_gherkin_story_packs.py

gherkin-stable-titles-check:
    @just _py uv run python scripts/check_gherkin_stable_titles.py

# PyPI: build artifacts then upload (`uv publish`; tokens/OIDC per RELEASING.md).
publish *ARGS:
    @just _py_cmd "uv build && uv publish {{ ARGS }}"
