"""Tests für die FastAPI-Validation-Helper aus app.main.

Issue #57 Befund #3 (Path-Traversal via drucksache) und #7 (Query-DoS).
Wir importieren die Helper direkt — keine TestClient-Roundtrip nötig,
weil die Funktionen reine Validierung sind und die FastAPI-Integration
in app.main den richtigen Aufrufpfad bereits vorgibt.
"""
from __future__ import annotations

import pytest
from fastapi import HTTPException

from app.validators import (
    MAX_SEARCH_QUERY_LEN,
    validate_drucksache,
    validate_search_query,
)


# ─────────────────────────────────────────────────────────────────────────────
# validate_drucksache (Befund #3 — Path-Traversal-Härtung)
# ─────────────────────────────────────────────────────────────────────────────


class TestValidateDrucksache:
    @pytest.mark.parametrize(
        "valid",
        [
            "8/6390",
            "18/12345",
            "23/3700",
            "20/4309",
            "8/6390(neu)",
            "23/3700-A",
        ],
    )
    def test_accepts_known_real_formats(self, valid):
        assert validate_drucksache(valid) == valid

    @pytest.mark.parametrize(
        "evil",
        [
            "../../etc/passwd",
            "8/6390/../../../etc/shadow",
            "8/6390;rm -rf /",
            "8/6390?bundesland=NRW",
            "<script>alert(1)</script>",
            "8/6390 OR 1=1",
            "",
            "/",
            "8//6390",
            "abc/def",
            "8/abc",
        ],
    )
    def test_rejects_path_traversal_and_injection(self, evil):
        with pytest.raises(HTTPException) as exc:
            validate_drucksache(evil)
        assert exc.value.status_code == 400


# ─────────────────────────────────────────────────────────────────────────────
# validate_search_query (Befund #7 — Query-Length-DoS)
# ─────────────────────────────────────────────────────────────────────────────


class TestValidateSearchQuery:
    def test_short_query_passes(self):
        assert validate_search_query("Klimaschutz") == "Klimaschutz"

    def test_at_limit_passes(self):
        q = "x" * MAX_SEARCH_QUERY_LEN
        assert validate_search_query(q) == q

    def test_over_limit_rejected(self):
        q = "x" * (MAX_SEARCH_QUERY_LEN + 1)
        with pytest.raises(HTTPException) as exc:
            validate_search_query(q)
        assert exc.value.status_code == 400
        assert "zu lang" in exc.value.detail.lower()

    def test_none_query_rejected(self):
        with pytest.raises(HTTPException) as exc:
            validate_search_query(None)  # type: ignore[arg-type]
        assert exc.value.status_code == 400

    def test_empty_string_passes(self):
        # Eine leere Query ist semantisch ok (Frontend nutzt sie für
        # "alle Drucksachen") — die Längen-Validierung soll nur den
        # absurd großen Fall blocken, nicht den leeren.
        assert validate_search_query("") == ""
