"""#1871 P2 — split-дома wide-corridor disclosure (за флагом, default OFF).

Tier A (same-building) матчит по address-regex (намеренно НЕ house_id — дом дробится
на несколько house_id). На split-доме разной этажности comp_min..comp_max растягивается
через несколько ценовых режимов → коридор range_low/range_high доходит до 148%/170%.
Коридор честно широкий (НЕ сужаем); disclosure только понижает confidence на ступень и
дописывает объяснение, НЕ трогая point/median/range.

Полный estimate-путь застаблен через harness из test_same_building_anchor.py
(_run_estimate). Плюс unit на helper _downgrade_confidence.
"""

from __future__ import annotations

import importlib.util
import os
from pathlib import Path
from typing import Any
from unittest.mock import patch

os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost/test_db")

import pytest

from app.core.config import settings
from app.services.estimator import _downgrade_confidence

# Переиспользуем harness _run_estimate / _make_payload из anchor-теста (полный
# estimate путь со всеми I/O застабленными).
_ANCHOR_TEST = Path(__file__).parent / "test_same_building_anchor.py"
_spec = importlib.util.spec_from_file_location("_anchor_harness", _ANCHOR_TEST)
assert _spec is not None and _spec.loader is not None
_h = importlib.util.module_from_spec(_spec)
_spec.loader.exec_module(_h)


# Split-дом: низкая секция (130k) … видовая высокая секция (360k) → коридор > 60%.
_WIDE_SPLIT_COMPS: list[dict[str, Any]] = [
    {"price_per_m2": 130_000, "area_m2": 60.0, "rooms": 2},
    {"price_per_m2": 150_000, "area_m2": 62.0, "rooms": 2},
    {"price_per_m2": 240_000, "area_m2": 58.0, "rooms": 2},
    {"price_per_m2": 360_000, "area_m2": 61.0, "rooms": 2},
]


def _payload():  # type: ignore[no-untyped-def]
    return _h._make_payload(area=60.0, rooms=2)


def _run(*, anchor_tier: str, comps=None, threshold: float = 0.6):  # type: ignore[no-untyped-def]
    with patch.object(settings, "estimate_wide_corridor_threshold", threshold):
        return _h._run_estimate(
            anchor_comps=_WIDE_SPLIT_COMPS if comps is None else comps,
            anchor_tier=anchor_tier,
            payload=_payload(),
        )


_DISCLOSURE_MARKER = "разбит на секции"


# ---------------------------------------------------------------------------
# Порог по умолчанию
# ---------------------------------------------------------------------------


def test_threshold_default_1_2() -> None:
    # 1.2: 0.6 фаерил бы на ~31% оценок (широкий коридор ≠ split-дом);
    # genuine split-дома аудита = 148-170% → 1.2 ловит только экстремальный хвост.
    assert settings.estimate_wide_corridor_threshold == 1.2


# ---------------------------------------------------------------------------
# Disclosure поведение
# ---------------------------------------------------------------------------


def test_tier_a_wide_corridor_downgrades_and_discloses() -> None:
    """Tier A + corridor_pct > threshold → confidence понижен + disclosure."""
    on = _run(anchor_tier="A")
    pct = (on.range_high_rub - on.range_low_rub) / on.median_price_rub
    assert pct > 0.6, "fixture должен давать коридор > 60%"
    assert _DISCLOSURE_MARKER in (on.confidence_explanation or "")
    # confidence понижен относительно no-fire baseline (порог выше коридора).
    off = _run(anchor_tier="A", threshold=99.0)
    assert _downgrade_confidence(off.confidence) == on.confidence
    assert on.confidence != off.confidence


def test_threshold_above_corridor_no_change() -> None:
    """Порог выше фактического коридора → ничего не делает (ни confidence, ни explanation)."""
    off = _run(anchor_tier="A", threshold=99.0)
    assert _DISCLOSURE_MARKER not in (off.confidence_explanation or "")


# Boundary-тесты вокруг ПРОД-порога: _WIDE_SPLIT_COMPS даёт коридор ≈1.045
# (estimator MAD-фильтрует более широкие спреды, поэтому проверяем границу
# через сам threshold, а не пытаемся сконструировать коридор >1.2).


def test_corridor_fires_when_above_threshold() -> None:
    """corridor_pct (≈1.045) > threshold (1.0) → disclosure фаерит (механизм работает)."""
    on = _run(anchor_tier="A", threshold=1.0)
    pct = (on.range_high_rub - on.range_low_rub) / on.median_price_rub
    assert pct > 1.0
    assert _DISCLOSURE_MARKER in (on.confidence_explanation or "")


def test_moderate_corridor_no_fire_at_prod_threshold_1_2() -> None:
    """Прод-дефолт 1.2: умеренный коридор (0.6<pct<1.2) НЕ фаерит — нет ложной
    атрибуции split-дома на ~31% оценок, которую дал бы старый порог 0.6."""
    on = _run(anchor_tier="A", threshold=1.2)  # _WIDE_SPLIT_COMPS ≈ 1.045
    pct = (on.range_high_rub - on.range_low_rub) / on.median_price_rub
    assert 0.6 < pct < 1.2, "moderate-fixture должен быть между 0.6 и 1.2"
    assert _DISCLOSURE_MARKER not in (on.confidence_explanation or "")


def test_does_not_touch_point_median_range() -> None:
    """Disclosure НЕ трогает point/median/range — только confidence+explanation."""
    off = _run(anchor_tier="A", threshold=99.0)
    on = _run(anchor_tier="A")
    assert on.median_price_rub == off.median_price_rub
    assert on.range_low_rub == off.range_low_rub
    assert on.range_high_rub == off.range_high_rub


def test_below_threshold_no_disclosure() -> None:
    """corridor_pct ниже порога → без изменений (порог поднят выше фактического)."""
    high_threshold = _run(anchor_tier="A", threshold=5.0)
    assert _DISCLOSURE_MARKER not in (high_threshold.confidence_explanation or "")


def test_non_tier_a_not_affected() -> None:
    """Не-Tier-A (Tier C) → disclosure не применяется."""
    c = _run(anchor_tier="C")
    assert _DISCLOSURE_MARKER not in (c.confidence_explanation or "")


# ---------------------------------------------------------------------------
# _downgrade_confidence helper
# ---------------------------------------------------------------------------


def test_downgrade_high_to_medium() -> None:
    assert _downgrade_confidence("high") == "medium"


def test_downgrade_medium_to_low() -> None:
    assert _downgrade_confidence("medium") == "low"


def test_downgrade_low_stays_low() -> None:
    assert _downgrade_confidence("low") == "low"


def test_downgrade_unknown_passthrough() -> None:
    # defensive: незнакомое значение возвращается как есть
    assert _downgrade_confidence("weird") == "weird"


if __name__ == "__main__":  # pragma: no cover
    raise SystemExit(pytest.main([__file__, "-q"]))
