"""Тесты reservation_lookup (#1091, #1062) — read-side lookup из land_reservation."""

from __future__ import annotations

from datetime import date
from typing import Any

from sqlalchemy.exc import OperationalError, ProgrammingError

from app.services.site_finder.reservation_lookup import parcel_reservations

# ── Моки БД (аналог test_ird_overlay_lookup.py) ───────────────────────────────


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)


# ── Фикстура строк ────────────────────────────────────────────────────────────

_ROWS = [
    {
        "reservation_kind": "изъятие",
        "basis_act": "Постановление Правительства СО № 509-ПП",
        "act_number": "509-ПП",
        "act_date": date(2024, 3, 12),
        "purpose": "реконструкция улицы Татищева",
        "doc_url": "https://pravo.gov66.ru/documents/view/509-pp",
    },
    {
        "reservation_kind": "резервирование",
        "basis_act": "Постановление Правительства СО № 210-ПП",
        "act_number": "210-ПП",
        "act_date": date(2024, 6, 5),
        "purpose": "строительство дороги",
        "doc_url": "https://pravo.gov66.ru/documents/view/210-pp",
    },
]


# ── Тесты ────────────────────────────────────────────────────────────────────


def test_maps_rows_correctly() -> None:
    """Строки из БД корректно маппируются в список словарей."""
    result = parcel_reservations(_FakeDB(_ROWS), "66:41:0101001:123")
    assert len(result) == 2
    assert result[0]["reservation_kind"] == "изъятие"
    assert result[0]["act_number"] == "509-ПП"
    assert result[0]["act_date"] == date(2024, 3, 12)
    assert result[1]["reservation_kind"] == "резервирование"


def test_expected_keys_present() -> None:
    """Каждый элемент содержит все ожидаемые ключи."""
    result = parcel_reservations(_FakeDB(_ROWS), "66:41:0101001:123")
    expected_keys = {
        "reservation_kind",
        "basis_act",
        "act_number",
        "act_date",
        "purpose",
        "doc_url",
    }
    for item in result:
        assert set(item.keys()) == expected_keys


def test_empty_when_no_rows() -> None:
    """Нет записей в БД → пустой список."""
    result = parcel_reservations(_FakeDB([]), "66:41:0101001:999")
    assert result == []


def test_empty_when_cad_num_none() -> None:
    """cad_num=None → пустой список, БД не вызывается."""
    result = parcel_reservations(_FakeDB(_ROWS), None)
    assert result == []


def test_empty_when_cad_num_empty_string() -> None:
    """cad_num='' → пустой список (falsy guard)."""
    result = parcel_reservations(_FakeDB(_ROWS), "")
    assert result == []


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


def test_graceful_on_programming_error() -> None:
    """ProgrammingError → [] без падения."""
    db = _FakeDB(raise_exc=ProgrammingError("stmt", {}, Exception("column not found")))
    result = parcel_reservations(db, "66:41:0101001:123")
    assert result == []
