"""Общий helper выбора прокси для curl_cffi-путей (#2163), за флагом USE_PROXY_POOL_CURL.

Инвариант ship-dark + fallback:
  - config.use_proxy_pool_curl=False (дефолт) ИЛИ proxy_provider=None → yield env-прокси
    (env_fallback_url) — curl-пути ходят ровно как сейчас, прод не меняется.
  - Флаг on + пул выдал lease → yield lease.url; на выходе mark_health(ok) + release(lease).
    ok=True если блок отработал без исключения, ok=False если внутри поднялось (бан/ошибка).
  - Флаг on + пул пуст/ошибка acquire → fallback на env_fallback_url, НЕ падаем (сбор цел).

release ВСЕГДА в finally — lease не должен течь, даже если fetch кинул. mark_health/release
обёрнуты в best-effort try (проблема пула не должна ронять сбор).
"""

from __future__ import annotations

import logging
from collections.abc import Iterator
from contextlib import contextmanager
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from scraper_kit.contracts import ProxyProvider, ScraperConfig

logger = logging.getLogger(__name__)


@contextmanager
def curl_proxy_url(
    config: ScraperConfig | None,
    proxy_provider: ProxyProvider | None,
    provider: str,
    *,
    env_fallback_url: str | None,
) -> Iterator[str | None]:
    """Отдать effective proxy-url для curl_cffi (`proxies={http/https: url}`).

    Args:
        config: ScraperConfig (читается флаг use_proxy_pool_curl). None → env-fallback.
        proxy_provider: пул прокси или None (off). None → env-fallback.
        provider: имя провайдера для affinity ("avito"/"cian"/"yandex"/...).
        env_fallback_url: прокси-url как сейчас (config.cian_proxy_url / scraper_proxy_url).

    Yields effective url (может быть None = прямое подключение, как и раньше).
    """
    use_pool = (
        config is not None
        and getattr(config, "use_proxy_pool_curl", False)
        and proxy_provider is not None
    )

    lease = None
    if use_pool:
        assert proxy_provider is not None  # для type-narrowing (use_pool это гарантирует)
        try:
            lease = proxy_provider.acquire(provider)
        except Exception:
            logger.warning(
                "proxy_pool: acquire(%s) failed — fallback to env proxy", provider, exc_info=True
            )
            lease = None

    if lease is None:
        # off / пул пуст / ошибка acquire → env как сейчас (сбор не ломаем).
        yield env_fallback_url
        return

    assert proxy_provider is not None
    ok = True
    try:
        yield lease.url
    except Exception:
        ok = False
        raise
    finally:
        # mark_health + release — best-effort: проблема пула не должна ронять сбор.
        try:
            proxy_provider.mark_health(lease, ok)
        except Exception:
            logger.warning("proxy_pool: mark_health failed for %s", provider, exc_info=True)
        try:
            proxy_provider.release(lease)  # ОБЯЗАТЕЛЬНО — lease не течёт
        except Exception:
            logger.warning("proxy_pool: release failed for %s", provider, exc_info=True)
