"""Smoke-proof для parity-harness'а (tests/support/parity.py) — issue #2304.

Доказывает, что harness реально ловит эквивалентность legacy ↔ scraper_kit на
РЕАЛЬНОЙ паре функций, а не на синтетике: `parse_detail_html` — parsing-ядро,
которое `app/api/v1/admin.py::scrape_avito_detail` (debug-роут ручного запуска
парсера) вызывает косвенно через `fetch_detail()` (fetch_detail = HTTP GET +
`parse_detail_html(html, url)`; сам parse — чистая функция, без сети/БД, что и
позволяет сравнить её offline на фиксированной HTML-фикстуре).

`app/services/scrapers/avito_detail.py::parse_detail_html` (legacy) и
`scraper_kit/providers/avito/detail.py::parse_detail_html` (kit) на момент
написания теста ИДЕНТИЧНЫ по телу функции (см. audit
`Scraper_Kit_Legacy_Dependency_Audit_0703` в vault) — различаются только
import-пути модулей, из которых берутся зависимости (`app.services.scrapers.*`
vs `scraper_kit.*`) и Strangler-инжекция `ScraperConfig` в соседних функциях
(`fetch_detail`, `_build_detail_session`), которую сам `parse_detail_html` не
использует. Это НЕ миграция admin.py (issue #2305+) — только доказательство
инструмента.

HTML-фикстура — тот же minimal-marker набор, что и в
`tests/test_avito_detail_parse.py::test_minimal_parse` (независимая копия
литерала, чтобы этот тест не зависел от другого test-модуля).
"""

# ruff: noqa: E501  # HTML-фикстура содержит длинные строки разметки

from __future__ import annotations

import dataclasses
import os

import pytest

# app.services.scrapers.avito_detail импортирует app.core.config.settings=Settings(),
# которому нужен DATABASE_URL. Офлайн-парсинг БД не трогает — фиктивный DSN достаточен
# (mirror tests/test_scraper_kit_avito_golden_parity.py — тест должен жить и без
# CI-уровневого DATABASE_URL из ci-tradein.yml/deploy-tradein.yml).
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost/test_db")

from scraper_kit.providers.avito.detail import (
    parse_detail_html as kit_parse_detail_html,
)

from app.services.scrapers.avito_detail import (
    parse_detail_html as legacy_parse_detail_html,
)
from tests.support.parity import ParityMismatchError, assert_parity

_DETAIL_HTML = """
<html><body>
<div data-marker="item-view/item-id">№ 7986882804 · 18 мая в 13:40 · 1899 просмотров (+ 12 сегодня)</div>
<span itemprop="price" content="11990000">11 990 000 ₽</span>
<div data-marker="item-map-wrapper" data-map-lat="56.797713" data-map-lon="60.609135" data-location-id="654070"></div>
<div data-marker="item-view/item-params">
  <ul>
    <li>Количество комнат: 3</li>
    <li>Общая площадь: 75 м²</li>
    <li>Площадь кухни: 15 м²</li>
    <li>Этаж: 20 из 26</li>
    <li>Балкон или лоджия: лоджия</li>
    <li>Ремонт: евро</li>
    <li>Способ продажи: свободная</li>
    <li>Условия продажи: возможна ипотека</li>
  </ul>
  <ul>
    <li>Тип дома: монолитный</li>
    <li>Этажей в доме: 26</li>
  </ul>
</div>
<a data-marker="nd-jk-details-button" href="/catalog/houses/ekaterinburg/ul_postovskogo_17a/3171365">Дом</a>
<div data-marker="domoteka-entry-block">
  <p data-marker="TeaserData.item">1 собственник</p>
  <p data-marker="TeaserData.item">Последняя смена собственника 5 мая 2020</p>
  <p data-marker="TeaserData.item">Не найдены ограничения и обременения</p>
  <p data-marker="TeaserData.item">Совпадают площадь, адрес и этаж</p>
</div>
<div data-marker="item-view/item-description">Отличная квартира в новом ЖК. Чкаловская 11-15 мин пешком.</div>
</body></html>
"""
_SOURCE_URL = "https://www.avito.ru/ekaterinburg/kvartiry/test_7986882804"


def test_legacy_and_kit_parse_detail_html_are_class_distinct() -> None:
    """Sanity-check ДО harness'а: подтверждает, зачем harness вообще нужен.

    legacy DetailEnrichment и kit DetailEnrichment — РАЗНЫЕ классы (разные
    модули) → обычный `==` даёт False, хотя данные идентичны. Именно это
    harness должен обходить через структурное сравнение (dataclasses.fields).
    """
    legacy_result = legacy_parse_detail_html(_DETAIL_HTML, _SOURCE_URL)
    kit_result = kit_parse_detail_html(_DETAIL_HTML, _SOURCE_URL)

    assert type(legacy_result) is not type(kit_result)
    assert legacy_result != kit_result  # dataclass __eq__ проверяет class identity первым
    assert dataclasses.asdict(legacy_result) == dataclasses.asdict(kit_result)


def test_parity_harness_confirms_avito_detail_parse_equivalence() -> None:
    """Реальное proof-of-concept использование harness'а (issues #2305-#2310 template)."""
    assert_parity(
        legacy_fn=legacy_parse_detail_html,
        kit_fn=kit_parse_detail_html,
        fixtures=[(_DETAIL_HTML, _SOURCE_URL)],
    )


def test_parity_harness_catches_real_field_divergence() -> None:
    """Доказывает, что harness реально ЛОВИТ расхождение на этой же реальной
    30+-полевой dataclass-форме — а не только сообщает "нет разницы" на двух
    genuinely-identical инстансах, как предыдущий тест.

    Мутируем один field (``price_rub``) в kit-результате через
    ``dataclasses.replace`` и убеждаемся, что harness падает с
    ``ParityMismatchError``, называющим именно этот field.
    """
    legacy_result = legacy_parse_detail_html(_DETAIL_HTML, _SOURCE_URL)
    kit_result = kit_parse_detail_html(_DETAIL_HTML, _SOURCE_URL)
    assert kit_result.price_rub is not None  # sanity: поле реально распарсилось из фикстуры

    mutated_kit_result = dataclasses.replace(kit_result, price_rub=kit_result.price_rub + 1)

    with pytest.raises(ParityMismatchError) as exc_info:
        assert_parity(
            legacy_fn=lambda: legacy_result,
            kit_fn=lambda: mutated_kit_result,
            fixtures=[()],
        )

    assert "price_rub" in str(exc_info.value)
