"""Parity-proof: `app.services.scrapers.ekb_geoportal_client` vs
`scraper_kit.providers.ekb_geoportal.client` (issue #2307, Group D).

`parse_feature_collection` (GeoJSON FeatureCollection → list[TopoBuilding],
area-weighted centroid) — чистая функция без сети/БД, поэтому сравнивается
offline через `tests.support.parity.assert_parity` (harness #2304). Legacy и
kit тела функции на момент написания теста ИДЕНТИЧНЫ (см. audit
`Scraper_Kit_Legacy_Dependency_Audit_0703` в vault) — единственное отличие —
import-путь модуля.

GeoJSON-фикстуры — независимая копия из
`tests/test_ekb_geoportal_ingest.py::test_parse_feature_collection_basic`,
чтобы этот тест не зависел от другого test-модуля.
"""

from __future__ import annotations

import dataclasses

import pytest
from scraper_kit.providers.ekb_geoportal.client import (
    TopoBuilding as KitTopoBuilding,
)
from scraper_kit.providers.ekb_geoportal.client import (
    parse_feature_collection as kit_parse_feature_collection,
)

from app.services.scrapers.ekb_geoportal_client import (
    TopoBuilding as LegacyTopoBuilding,
)
from app.services.scrapers.ekb_geoportal_client import (
    parse_feature_collection as legacy_parse_feature_collection,
)
from tests.support.parity import ParityMismatchError, assert_parity

# A unit square [0,0]-[2,2] → centroid (1, 1) in (lon, lat).
_SQUARE = [[[[0.0, 0.0], [2.0, 0.0], [2.0, 2.0], [0.0, 2.0], [0.0, 0.0]]]]


def _multipolygon(coords: list) -> dict:
    return {"type": "MultiPolygon", "coordinates": coords}


_FEATURE_COLLECTION = {
    "type": "FeatureCollection",
    "features": [
        {
            "type": "Feature",
            "geometry": _multipolygon(_SQUARE),
            "properties": {
                "topo_street": "Космонавтов",
                "topo_num_house": "7б",
                "topo_floor": 9,
                "topo_purpose": "жилое",
                "topo_material": "3",
                "key": 12345,
            },
        },
        {
            # без street/house — должен быть пропущен обоими путями
            "type": "Feature",
            "geometry": _multipolygon(_SQUARE),
            "properties": {"topo_street": "", "topo_num_house": "5"},
        },
    ],
}


def test_legacy_and_kit_topo_building_are_class_distinct() -> None:
    """Sanity-check ДО harness'а: legacy/kit TopoBuilding — РАЗНЫЕ классы
    (разные модули) → обычный `==` даёт False, хотя данные идентичны."""
    legacy_result = legacy_parse_feature_collection(_FEATURE_COLLECTION)
    kit_result = kit_parse_feature_collection(_FEATURE_COLLECTION)

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


def test_parity_harness_confirms_ekb_geoportal_parse_equivalence() -> None:
    """Реальное использование harness'а для EKB Geoportal client (issue #2307)."""
    assert_parity(
        legacy_fn=legacy_parse_feature_collection,
        kit_fn=kit_parse_feature_collection,
        fixtures=[(_FEATURE_COLLECTION,)],
    )


def test_parity_harness_catches_real_field_divergence() -> None:
    """Harness реально ЛОВИТ расхождение — мутируем ``floors`` в kit-результате
    и убеждаемся, что harness падает с ``ParityMismatchError``, называющим
    именно этот field."""
    legacy_result = legacy_parse_feature_collection(_FEATURE_COLLECTION)
    kit_result = kit_parse_feature_collection(_FEATURE_COLLECTION)
    assert kit_result[0].floors == 9  # sanity: поле реально распарсилось

    mutated_kit_building = dataclasses.replace(kit_result[0], floors=1)
    assert isinstance(mutated_kit_building, KitTopoBuilding)
    assert isinstance(legacy_result[0], LegacyTopoBuilding)

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

    assert "floors" in str(exc_info.value)


def test_legacy_and_kit_empty_and_malformed_inputs_match() -> None:
    """Graceful-degradation ветки (пустой/битый payload) дают одинаковый []
    на обоих путях."""
    for payload in ({}, {"features": "nope"}, {"features": [None, 42]}):
        assert legacy_parse_feature_collection(payload) == []
        assert kit_parse_feature_collection(payload) == []
