"""test_house_imv_backfill_browser_flag.py — #915 Stage 3.

Проверяет проводку флага avito_imv_use_browser_fetcher в backfill_house_imv:
  - флаг ON  → конструируется один BrowserFetcher(source="avito") на весь батч,
               и он прокидывается в _process_one_house(browser_fetcher=...).
  - флаг OFF → BrowserFetcher НЕ конструируется, browser_fetcher=None (старый путь).

DB и _process_one_house мокаются — реальный камуфокс/curl/Postgres не нужны.
"""

from __future__ import annotations

import os
from typing import Any, ClassVar
from unittest.mock import MagicMock

import pytest

# settings нужен DSN на импорте (как в соседних тестах) — fake-db, статический.
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test")

from app.services import house_imv_backfill


class _FakeBrowserFetcher:
    """Поддельный async-CM: считает конструкции/входы, возвращает себя из __aenter__."""

    instances: ClassVar[list[_FakeBrowserFetcher]] = []

    def __init__(self, source: str = "avito", **_: Any) -> None:
        self.source = source
        self.entered = False
        _FakeBrowserFetcher.instances.append(self)

    async def __aenter__(self) -> _FakeBrowserFetcher:
        self.entered = True
        return self

    async def __aexit__(self, *_: object) -> None:
        return None


def _fake_db_with_one_row() -> MagicMock:
    """MagicMock-Session, чей execute(...).mappings().all() отдаёт один дом."""
    db = MagicMock()
    row = {"id": 42, "address": "ЕКБ, ул. X, 1", "full_address": None, "lat": 56.8, "lon": 60.6}
    db.execute.return_value.mappings.return_value.all.return_value = [row]
    return db


async def test_backfill_flag_on_constructs_browser_and_threads_it(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    _FakeBrowserFetcher.instances.clear()
    monkeypatch.setattr(house_imv_backfill.settings, "avito_imv_use_browser_fetcher", True)
    monkeypatch.setattr(house_imv_backfill, "BrowserFetcher", _FakeBrowserFetcher)

    captured: dict[str, Any] = {}

    async def _fake_process(db: Any, house: dict, *, browser_fetcher: Any = None) -> str:
        captured["browser_fetcher"] = browser_fetcher
        return "ok"

    monkeypatch.setattr(house_imv_backfill, "_process_one_house", _fake_process)

    db = _fake_db_with_one_row()
    await house_imv_backfill.backfill_house_imv(db, batch_size=10)

    # Ровно один BrowserFetcher(source="avito"), вошли в контекст.
    assert len(_FakeBrowserFetcher.instances) == 1
    bf = _FakeBrowserFetcher.instances[0]
    assert bf.source == "avito"
    assert bf.entered is True
    # И он прокинут в _process_one_house.
    assert captured["browser_fetcher"] is bf


async def test_backfill_flag_off_no_browser_and_none_threaded(
    monkeypatch: pytest.MonkeyPatch,
) -> None:
    _FakeBrowserFetcher.instances.clear()
    monkeypatch.setattr(house_imv_backfill.settings, "avito_imv_use_browser_fetcher", False)
    monkeypatch.setattr(house_imv_backfill, "BrowserFetcher", _FakeBrowserFetcher)

    captured: dict[str, Any] = {}

    async def _fake_process(db: Any, house: dict, *, browser_fetcher: Any = None) -> str:
        captured["browser_fetcher"] = browser_fetcher
        return "ok"

    monkeypatch.setattr(house_imv_backfill, "_process_one_house", _fake_process)

    db = _fake_db_with_one_row()
    await house_imv_backfill.backfill_house_imv(db, batch_size=10)

    # Флаг OFF → BrowserFetcher не конструируется, browser_fetcher=None.
    assert _FakeBrowserFetcher.instances == []
    assert captured["browser_fetcher"] is None
