"""РИАСУРТ Свердл gate-lookup для analyze_parcel (#108, multi-city scaling).

Читает ``riasurt_sverdl`` (наполняется harvest-task riasurt_sverdl_harvest.py) и отдаёт зоны
РИАСУРТ Свердл, пересекающие участок: тер.зона / функц.зона / красные линии / СЗЗ / ЗСО /
затопление / КРТ. Только для участков агломерации ЕКБ (ОКРАИНЫ — Берёзовский, В.Пышма,
Среднеуральск, Арамиль, Сысерть), НЕ для ЕКБ-сити (тот не покрыт РИАСУРТ Свердл).

Gate-форма (``response["gate"]["riasurt"]``) собирается из topic-бакетов:
  tier / func_zone / red_lines / szz / szo / flood_zone / krt + raw-список overlaps.

Graceful: нет таблицы (pre-migration) / пустой WKT / БД-ошибка → пустой gate (analyze не падает).
Зеркалит стиль ``ird_overlay_lookup.py``.
"""

from __future__ import annotations

import logging
from typing import Any

from sqlalchemy import text
from sqlalchemy.exc import DataError, OperationalError, ProgrammingError
from sqlalchemy.orm import Session

logger = logging.getLogger(__name__)

# Кадастровый район ЕКБ-сити — 66:41. Агломерация (окраины) — прочие районы 66:xx
# (Берёзовский 66:35, В.Пышма/Среднеуральск 66:62, Арамиль/Сысерть 66:25, ...).
_EKB_CITY_PREFIX = "66:41"

# Пустой gate-результат — sentinel (НЕ мутировать).
RIASURT_EMPTY_GATE: dict[str, Any] = {
    "applicable": False,
    "tier": None,
    "func_zone": None,
    "red_lines": False,
    "szz": False,
    "szo": False,
    "flood_zone": False,
    "krt": False,
    "overlaps": [],
}

# Пересечения участка с зонами РИАСУРТ. geom в БД — EPSG:3857; участок передаём WKT в 4326 и
# трансформируем в 3857 для ST_Intersects по GIST idx_riasurt_sverdl_geom. CAST psycopg v3.
_RIASURT_OVERLAP_SQL = text(
    """
    SELECT source_layer_id, layer_topic, mo_name, obshnz, description
    FROM riasurt_sverdl
    WHERE ST_Intersects(
            geom,
            ST_Transform(ST_GeomFromText(CAST(:parcel_wkt AS text), 4326), 3857)
          )
    ORDER BY layer_topic, source_layer_id
    """
)


def is_in_aglomeration_but_not_ekb(cad: str | None) -> bool:
    """True если участок в агломерации ЕКБ, но НЕ в самом ЕКБ-сити (66:41).

    РИАСУРТ Свердл покрывает только окраины агломерации (Берёзовский, В.Пышма,
    Среднеуральск, Арамиль, Сысерть) — кадастровые районы 66:xx, кроме 66:41.
    ЕКБ-сити (66:41) и участки вне Свердл (не 66:*) → False.

    Args:
        cad: кадастровый номер участка ('66:35:...'). None/пусто → False.

    Returns:
        bool.
    """
    if not cad:
        return False
    cad = cad.strip()
    if not cad.startswith("66:"):
        return False
    return not cad.startswith(_EKB_CITY_PREFIX + ":") and cad != _EKB_CITY_PREFIX


def parcel_riasurt_gate(
    db: Session,
    parcel_wkt: str | None,
    cad: str | None,
) -> dict[str, Any]:
    """Gate-блок РИАСУРТ Свердл для участка агломерации ЕКБ.

    Если участок не в агломерации (или в ЕКБ-сити) → RIASURT_EMPTY_GATE (applicable=False).
    Иначе ST_Intersects по riasurt_sverdl и сборка topic-бакетов.

    Args:
        db: сессия.
        parcel_wkt: геометрия участка WKT (EPSG:4326). None → пустой gate.
        cad: кадастровый номер (для is_in_aglomeration_but_not_ekb).

    Returns:
        dict с полями tier / func_zone / red_lines / szz / szo / flood_zone / krt + overlaps.
        Пусто при отсутствии участка / таблицы / пересечений / вне агломерации.
    """
    if not parcel_wkt or not is_in_aglomeration_but_not_ekb(cad):
        return dict(RIASURT_EMPTY_GATE)

    try:
        with db.begin_nested():
            rows = db.execute(_RIASURT_OVERLAP_SQL, {"parcel_wkt": parcel_wkt}).mappings().all()
    except (OperationalError, ProgrammingError, DataError) as exc:
        logger.warning("parcel_riasurt_gate: таблица/запрос недоступны, skip: %s", exc)
        return dict(RIASURT_EMPTY_GATE)
    except Exception as exc:
        logger.warning("parcel_riasurt_gate: неожиданная ошибка, skip: %s", exc)
        return dict(RIASURT_EMPTY_GATE)

    gate: dict[str, Any] = {
        "applicable": True,
        "tier": None,  # description зоны topic='territorial_zone'
        "func_zone": None,  # description зоны topic='functional_zone'
        "red_lines": False,
        "szz": False,
        "szo": False,
        "flood_zone": False,
        "krt": False,
        "overlaps": [],
    }
    for r in rows:
        topic = r["layer_topic"]
        gate["overlaps"].append(
            {
                "source_layer_id": r["source_layer_id"],
                "layer_topic": topic,
                "mo_name": r["mo_name"],
                "obshnz": r["obshnz"],
                "description": r["description"],
            }
        )
        if topic == "territorial_zone" and gate["tier"] is None:
            gate["tier"] = r["description"] or r["obshnz"]
        elif topic == "functional_zone" and gate["func_zone"] is None:
            gate["func_zone"] = r["description"] or r["obshnz"]
        elif topic == "red_lines":
            gate["red_lines"] = True
        elif topic == "szz":
            gate["szz"] = True
        elif topic == "szo":
            gate["szo"] = True
        elif topic == "flood_zone":
            gate["flood_zone"] = True
        elif topic == "krt":
            gate["krt"] = True

    return gate


__all__ = [
    "RIASURT_EMPTY_GATE",
    "is_in_aglomeration_but_not_ekb",
    "parcel_riasurt_gate",
]
