"""Regression-тест для issue #2330 (Group F2 эпика #2277 scraper_kit migration).

Баг: `scraper_kit/providers/avito/detail.py::build_warmed_session()` строил detail-
сессию через `_build_detail_session()` БЕЗ параметра `config` вообще — в отличие от
`fetch_detail()` в том же файле, у которой `config=` есть и штатно пробрасывает
sticky-прокси в `_build_detail_session(config)`. Т.к. kit-`_build_detail_session` (в
отличие от legacy `app/services/scrapers/avito_detail.py`, который читает
`settings.scraper_proxy_url` напрямую) читает прокси ТОЛЬКО из инжектируемого
`config.scraper_proxy_url`, отсутствие параметра означало, что `build_warmed_session`
физически не могло получить прокси ни при каких условиях. Сегодняшний единственный
caller (`avito_detail_backfill.py`) всё ещё импортирует эту функцию из legacy-модуля,
так что прод-путь этим фиксом не затронут — это advance-prep: как только caller
переключится на kit (avito_detail_backfill_use_curl=True — прод-дефолт режим), без
этого фикса он тихо терял бы sticky backconnect-proxy на warm-batch операциях. См.
`test_scraper_kit_group_c_backfill_kit_parity.py` (issue #2310), который явно
документирует этот баг как flagged follow-up.

Этот файл доказывает РАЗНИЦУ в поведении, а не просто "функция не падает":
  1. `test_build_warmed_session_signature_now_accepts_config` — до фикса вызов
     `build_warmed_session(config=...)` был бы `TypeError` (функция принимала 0
     параметров). Сигнатура теперь содержит `config`.
  2. `test_build_warmed_session_with_config_propagates_real_proxy_to_session` —
     реальный (не замоканный) `curl_cffi.requests.AsyncSession`, построенный
     `build_warmed_session(config=...)`, содержит РЕАЛЬНЫЙ `proxy_url` из config в
     `session.proxies` — то же самое поведение, что и `fetch_detail(config=...)`.
  3. `test_build_warmed_session_without_config_has_no_proxy` — вызов без `config`
     (дефолт `None`, как было ДО фикса единственно возможное поведение) сессия
     остаётся без прокси — документирует, что caller обязан явно передать `config`,
     иначе прокси молча теряется (это и есть остающийся риск в
     `app/tasks/avito_detail_backfill.py`, отдельный будущий шаг вне scope #2330).

`warm_up_session` патчится no-op'ом — тест проверяет ТОЛЬКО построение сессии
(`_build_detail_session`), не сетевой прогрев.
"""

from __future__ import annotations

import inspect
from types import SimpleNamespace
from unittest.mock import AsyncMock, patch

from scraper_kit.providers.avito import detail as kit_detail
from scraper_kit.providers.avito.detail import build_warmed_session


def _fake_config(proxy_url: str | None) -> SimpleNamespace:
    """Минимальный duck-typed ScraperConfig — _build_detail_session читает только
    `.scraper_proxy_url` (structural typing, `Protocol` не требует явной реализации)."""
    return SimpleNamespace(scraper_proxy_url=proxy_url)


def test_build_warmed_session_signature_now_accepts_config() -> None:
    """До фикса #2330 `build_warmed_session()` не принимала параметров вовсе —
    `build_warmed_session(config=cfg)` падал бы `TypeError: unexpected keyword
    argument 'config'`. Проверяем, что параметр реально появился в сигнатуре."""
    params = inspect.signature(build_warmed_session).parameters
    assert "config" in params
    assert params["config"].default is None


async def test_build_warmed_session_with_config_propagates_real_proxy_to_session() -> None:
    """С `config.scraper_proxy_url` заданным — построенная curl_cffi-сессия реально
    несёт этот proxy_url (не мок: инспектируем настоящий AsyncSession.proxies)."""
    proxy_url = "http://user:pass@mproxy.local:14619"
    config = _fake_config(proxy_url)

    with patch.object(kit_detail, "warm_up_session", AsyncMock(return_value=True)):
        session = await build_warmed_session(config=config)  # type: ignore[arg-type]
    try:
        assert session.proxies == {"http": proxy_url, "https": proxy_url}
    finally:
        await session.close()


async def test_build_warmed_session_without_config_has_no_proxy() -> None:
    """Без `config` (дефолт, единственное поведение ДО фикса) сессия строится без
    прокси — ровно баг #2330: caller, не передающий config, молча теряет sticky-proxy."""
    with patch.object(kit_detail, "warm_up_session", AsyncMock(return_value=True)):
        session = await build_warmed_session()
    try:
        assert not session.proxies
    finally:
        await session.close()
