"""VCR.py configuration for recording and replaying HTTP interactions.

Provides VCR.py configuration for deterministic, offline testing of
axm-bib API clients against recorded HTTP responses.

Recording new cassettes
-----------------------
1. Set ``AXM_BIB_VCR_RECORD=1`` in your environment.
2. Run: ``uv run pytest tests/integration/vcr -m vcr -v``
3. Cassettes are saved to ``tests/integration/vcr/cassettes/``.
4. Verify scrubbing before committing (no API keys in YAML).

Replay mode (default / CI)
--------------------------
Cassettes are replayed without network access.  If a cassette is
missing the test is skipped with a clear message.
"""

from __future__ import annotations

import os
from typing import Any
from urllib.parse import parse_qs, urlencode, urlparse, urlunparse

import pytest
import vcr  # type: ignore[import-untyped]

# ---------------------------------------------------------------------------
# Scrubbing — remove sensitive values before writing cassettes
# ---------------------------------------------------------------------------

_S2_API_KEY_HEADER = "x-api-key"


def _scrub_request(request: Any) -> Any:
    """Remove API keys and emails from recorded requests."""
    # Scrub S2 API key header
    if _S2_API_KEY_HEADER in request.headers:
        request.headers[_S2_API_KEY_HEADER] = "SCRUBBED"

    # Scrub Authorization header
    if "Authorization" in request.headers:
        request.headers["Authorization"] = "SCRUBBED"

    # Scrub Unpaywall email from query params
    if request.uri:
        parsed = urlparse(request.uri)
        qs = parse_qs(parsed.query, keep_blank_values=True)
        if "email" in qs:
            qs["email"] = ["SCRUBBED"]
            new_query = urlencode(qs, doseq=True)
            request.uri = urlunparse(parsed._replace(query=new_query))

    return request


def _scrub_response(response: dict[str, Any]) -> dict[str, Any]:
    """Remove sensitive data from recorded responses."""
    headers = response.get("headers", {})
    # Strip Set-Cookie headers entirely
    headers.pop("Set-Cookie", None)
    headers.pop("set-cookie", None)
    return response


# ---------------------------------------------------------------------------
# Record mode — controlled by env var
# ---------------------------------------------------------------------------

_record_env = os.environ.get("AXM_BIB_VCR_RECORD", "").lower()
_record_mode = "new_episodes" if _record_env in ("1", "true", "yes") else "none"

_CASSETTE_DIR = os.path.join(os.path.dirname(__file__), "cassettes")

# ---------------------------------------------------------------------------
# VCR instance
# ---------------------------------------------------------------------------

axm_bib_vcr = vcr.VCR(
    cassette_library_dir=_CASSETTE_DIR,
    record_mode=_record_mode,
    match_on=["method", "scheme", "host", "port", "path", "query"],
    before_record_request=_scrub_request,
    before_record_response=_scrub_response,
    decode_compressed_response=True,
)


# ---------------------------------------------------------------------------
# Pytest fixture — auto-apply cassette per test
# ---------------------------------------------------------------------------


@pytest.fixture
def vcr_cassette(request: pytest.FixtureRequest) -> Any:
    """Apply a VCR cassette named after the current test.

    If the cassette file doesn't exist and record mode is ``none``,
    the test is skipped with a helpful message.
    """
    cassette_name = f"{request.node.name}.yaml"
    cassette_path = os.path.join(_CASSETTE_DIR, cassette_name)

    if _record_mode == "none" and not os.path.exists(cassette_path):
        pytest.skip(
            f"Cassette {cassette_name!r} not found. "
            "Run with AXM_BIB_VCR_RECORD=1 to record."
        )

    with axm_bib_vcr.use_cassette(cassette_path) as cass:
        yield cass
