"""Shared pytest fixtures for the Peblar test suite."""

from __future__ import annotations

import asyncio
import inspect
from types import SimpleNamespace
from typing import TYPE_CHECKING, Any

import aiohttp
import pytest
from aioresponses import core as aioresponses_core

if TYPE_CHECKING:
    from collections.abc import Generator


AIOHTTP_REQUIRES_STREAM_WRITER = (
    "stream_writer" in inspect.signature(aiohttp.ClientResponse.__init__).parameters
)

# aiohttp 3.14+ expects a stream_writer object exposing an `output_size` attribute.
DEFAULT_STREAM_WRITER = SimpleNamespace(output_size=0)


class AioresponsesClientResponse(aioresponses_core.ClientResponse):
    """Backwards-compatible ClientResponse for aioresponses."""

    def __init__(self, *args: Any, **kwargs: Any) -> None:
        """Initialize and provide a stream_writer for aiohttp 3.14+."""
        if AIOHTTP_REQUIRES_STREAM_WRITER:
            kwargs.setdefault("stream_writer", DEFAULT_STREAM_WRITER)
        super().__init__(*args, **kwargs)


@pytest.fixture(scope="session", autouse=True)
def _setup_aioresponses_aiohttp_compat() -> Generator[None, None, None]:
    """Patch aioresponses ClientResponse for aiohttp compatibility in tests."""
    if not AIOHTTP_REQUIRES_STREAM_WRITER:
        yield
        return

    with pytest.MonkeyPatch.context() as monkeypatch:
        monkeypatch.setattr(
            aioresponses_core,
            "ClientResponse",
            AioresponsesClientResponse,
        )
        yield


@pytest.fixture(autouse=True)
def _fast_retries(monkeypatch: pytest.MonkeyPatch) -> None:
    """Make tenacity's exponential backoff instant during tests.

    Tenacity sleeps via ``await asyncio.sleep(...)``; we swap that for a
    zero-delay version so the real retry logic still exercises, just
    without the exponential wall-clock cost.
    """
    real_sleep = asyncio.sleep

    async def instant_sleep(_delay: float, result: Any = None) -> Any:
        return await real_sleep(0, result)

    monkeypatch.setattr(asyncio, "sleep", instant_sleep)
