"""Тесты parcel_functional_zones (#1058) — read-side lookup функциональных зон генплана."""

from __future__ import annotations

from typing import Any

from sqlalchemy.exc import OperationalError, ProgrammingError

from app.services.site_finder.functional_zone_lookup import parcel_functional_zones


class _Result:
    def __init__(self, rows: list[dict[str, Any]]) -> None:
        self._rows = rows

    def mappings(self) -> _Result:
        return self

    def all(self) -> list[dict[str, Any]]:
        return self._rows


class _FakeDB:
    def __init__(
        self,
        rows: list[dict[str, Any]] | None = None,
        raise_exc: Exception | None = None,
    ) -> None:
        self._rows = rows or []
        self._raise = raise_exc

    def execute(self, sql: Any, params: dict[str, Any] | None = None) -> _Result:
        if self._raise is not None:
            raise self._raise
        return _Result(self._rows)


_WKT = "POLYGON((60.5 56.8, 60.6 56.8, 60.6 56.9, 60.5 56.9, 60.5 56.8))"


def test_returns_zones_for_parcel() -> None:
    """Обычный случай: строки из БД → список dict с нужными ключами."""
    rows = [
        {
            "zone_type": "Жилые зоны",
            "status": "Существующий",
            "area_ha": 15.3,
            "zone_class_code": "Ж",
        },
        {
            "zone_type": "Общественные зоны",
            "status": "Планируемый",
            "area_ha": None,
            "zone_class_code": "О",
        },
    ]
    result = parcel_functional_zones(_FakeDB(rows), _WKT)

    assert len(result) == 2
    first = result[0]
    assert first["zone_type"] == "Жилые зоны"
    assert first["status"] == "Существующий"
    assert first["area_ha"] == 15.3
    assert first["zone_class_code"] == "Ж"
    second = result[1]
    assert second["area_ha"] is None  # NULL → None (не падает)


def test_empty_when_no_wkt() -> None:
    """parcel_wkt=None → пустой список без запроса к БД."""
    result = parcel_functional_zones(_FakeDB([{"zone_type": "Жилые зоны"}]), None)
    assert result == []


def test_empty_when_no_overlap() -> None:
    """БД вернула 0 строк → пустой список."""
    result = parcel_functional_zones(_FakeDB([]), _WKT)
    assert result == []


def test_graceful_when_table_missing_operational_error() -> None:
    """OperationalError (таблица не задеплоена) → [] без падения."""
    db = _FakeDB(raise_exc=OperationalError("stmt", {}, Exception("no such table")))
    result = parcel_functional_zones(db, _WKT)
    assert result == []


def test_graceful_when_table_missing_programming_error() -> None:
    """ProgrammingError (e.g. relation не существует) → [] без падения."""
    db = _FakeDB(raise_exc=ProgrammingError("stmt", {}, Exception("relation does not exist")))
    result = parcel_functional_zones(db, _WKT)
    assert result == []


def test_empty_string_wkt_treated_as_falsy() -> None:
    """Пустая строка wkt → пустой список (falsy guard)."""
    result = parcel_functional_zones(_FakeDB([]), "")
    assert result == []
