"""Schemathesis contract tests scoped to the TTP Tagging API surface.

E.3.17 of ``development/TTP_TAGGING.md``. The full ``test_schemathesis``
suite fuzzes every endpoint with ``max_examples=3000`` — slow and
overkill when iterating on TTP-routes-only changes (E.3.13–E.3.16).
This file filters by the OpenAPI ``tags=["TTP Tagging"]`` annotation
the eight TTP routes carry, runs against the same live uvicorn
subprocess the wider suite spins up, and applies the same check
battery so a 4xx-shape regression on a TTP route fails here without
waiting on the rest of the API.

Routes covered (all decorated ``tags=["TTP Tagging"]``):

* ``GET    /api/v1/ttp/techniques``
* ``GET    /api/v1/ttp/by-identity/{identity_uuid}``
* ``GET    /api/v1/ttp/by-attacker/{attacker_uuid}``
* ``GET    /api/v1/ttp/by-campaign/{campaign_uuid}``
* ``GET    /api/v1/ttp/by-session/{session_id}``
* ``GET    /api/v1/ttp/rules``
* ``POST   /api/v1/ttp/rules/{rule_id}/state``
* ``DELETE /api/v1/ttp/rules/{rule_id}/state``
* ``GET    /api/v1/ttp/export/navigator``
* ``GET    /api/v1/ttp/export/navigator/identity/{identity_uuid}``
"""
from __future__ import annotations

import pytest
import schemathesis as st
from hypothesis import HealthCheck, Verbosity, settings

from tests.api.test_schemathesis import (
    ALL_CHECKS,
    AUTH_CHECKS,
    LIVE_SERVER_URL,
    before_call as _shared_before_call,  # noqa: F401  (registers @st.hook)
)

# Reuse the schema fetched against the same uvicorn subprocess started
# by ``test_schemathesis``. Filtering by tag keeps the TTP suite a
# fast, focused contract gate without re-spinning the server.
TTP_SCHEMA = st.openapi.from_url(
    f"{LIVE_SERVER_URL}/openapi.json",
).include(tag="TTP Tagging")


@pytest.mark.fuzz
@TTP_SCHEMA.parametrize()
@settings(
    max_examples=400,
    deadline=None,
    verbosity=Verbosity.normal,
    suppress_health_check=[
        HealthCheck.filter_too_much,
        HealthCheck.too_slow,
        HealthCheck.data_too_large,
    ],
)
def test_ttp_schema_compliance(case):
    """Per-TTP-route schema compliance — valid + invalid inputs."""
    case.call_and_validate(checks=ALL_CHECKS)


@pytest.mark.fuzz
@TTP_SCHEMA.parametrize()
@settings(
    max_examples=120,
    deadline=None,
    verbosity=Verbosity.normal,
    suppress_health_check=[
        HealthCheck.filter_too_much,
        HealthCheck.too_slow,
    ],
)
def test_ttp_auth_enforcement(case):
    """Every TTP route rejects requests without a Bearer token (401).

    The mutation endpoints additionally require ``admin`` (server-side
    ``require_admin``); the authless probe doesn't distinguish 401 vs
    403 here — the ``ignored_auth`` check just asserts that an absent
    token never lands the request inside the handler with a usable
    identity.
    """
    case.headers = {
        k: v for k, v in (case.headers or {}).items()
        if k.lower() != "authorization"
    }
    case.call_and_validate(checks=AUTH_CHECKS)
