"""Пин SQL-формы competitors._SOLD_COUNT_SQL (perf follow-up эпика #1953, пункт #1).

Регрессия #1964→hunt: запрос JOIN'ил v_objective_lots_latest, чей DISTINCT ON по
ВСЕЙ 1.76M-таблице материализуется ДО фильтра маппинга (qual не проталкивается ниже
view-DISTINCT ON) → Parallel Seq Scan + external sort (~6896 ms, ~213 MB temp) на
каждый cold /analyze. FIX — inline-pushdown: фильтруем objective_complex_mapping в
CTE, затем DISTINCT ON по СЫРОЙ objective_lots с JOIN ON project_name (его
обслуживает objective_lots_project_idx) → дедуп лишь по нужным ЖК (~437 ms).

Эти тесты — строковые инварианты на скомпилированном SQL (без живой БД), чтобы
будущий рефактор случайно не вернул view-вариант и не сломал physflat-дедуп/
fan-out-защиту. Вывод побайтово идентичен view-варианту (hunt: 7082=7082, 0
mismatch) — поведение не меняется, меняется только план.
"""

from __future__ import annotations

import os
import re

os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test")

from app.services.site_finder.competitors import _SOLD_COUNT_SQL, _SOLD_PREMISE_KIND

_SQL = str(_SOLD_COUNT_SQL)
_SQL_FLAT = re.sub(r"\s+", " ", _SQL).lower()


def test_sold_count_reads_raw_objective_lots_not_view() -> None:
    """Читаем СЫРУЮ objective_lots inline, НЕ physflat-VIEW (иначе вернётся
    regression: full-table DISTINCT ON до фильтра маппинга → seq-scan+spill)."""
    assert "v_objective_lots_latest" not in _SQL_FLAT
    assert re.search(r"\bjoin\s+objective_lots\b", _SQL_FLAT)


def test_sold_count_uses_inline_distinct_on_physflat_key() -> None:
    """physflat-дедуп делается inline через DISTINCT ON по полному physflat-ключу
    (project_name, corpus_name, section, floor, lot_number) — НЕ через view."""
    m = re.search(r"distinct on \((.*?)\)", _SQL_FLAT, re.DOTALL)
    assert m is not None, "ожидался inline DISTINCT ON"
    key = m.group(1)
    for col in ("project_name", "corpus_name", "section", "floor", "lot_number"):
        assert col in key, f"physflat-ключ должен включать {col}"


def test_sold_count_orders_latest_snapshot_first() -> None:
    """ORDER BY последним снапшотом вперёд (snapshot_date DESC, id DESC) — DISTINCT ON
    берёт первую строку группы → последний снапшот физлота."""
    assert "snapshot_date desc" in _SQL_FLAT
    assert "id desc" in _SQL_FLAT
    # tie-break: id DESC должен идти ПОСЛЕ snapshot_date DESC.
    assert _SQL_FLAT.index("snapshot_date desc") < _SQL_FLAT.index("id desc")


def test_sold_count_filters_mapping_in_cte_before_join() -> None:
    """Фильтр маппинга (domrf_obj_id = ANY) проталкивается в CTE ДО DISTINCT ON —
    суть pushdown'а (дедуп лишь по нужным ЖК, а не по всей таблице)."""
    assert "objective_complex_mapping" in _SQL_FLAT
    assert ":obj_ids" in _SQL
    join_at = _SQL_FLAT.index("join objective_lots")
    filter_at = _SQL_FLAT.index("domrf_obj_id = any(:obj_ids)")
    assert filter_at < join_at, "фильтр маппинга должен предшествовать JOIN objective_lots"


def test_sold_count_keeps_distinct_objective_lot_id_fanout_safety() -> None:
    """COUNT(DISTINCT objective_lot_id) сохранён (fan-out-safety из #1964: маппинг
    1:N по domrf_obj_id)."""
    assert "count(distinct objective_lot_id)" in _SQL_FLAT


def test_sold_count_keeps_sold_predicate() -> None:
    """sold-предикат — зеркало market_metrics._STOCK_SQL: is_sold OR contract_date
    NOT NULL OR status='продан'."""
    assert "is_sold is true" in _SQL_FLAT
    assert "contract_date is not null" in _SQL_FLAT
    assert "= 'продан'" in _SQL_FLAT


def test_sold_count_filters_premise_kind_quartira() -> None:
    """premise_kind-фильтр на месте (бинд) и дефолт = 'квартира' (без него
    проданные паркинги/кладовые считались бы как квартиры)."""
    assert ":premise_kind" in _SQL
    assert _SOLD_PREMISE_KIND == "квартира"


def test_sold_count_no_double_colon_cast() -> None:
    """psycopg v3 / backend.md: никаких :name::type (игнорируется парсером)."""
    assert not re.search(r":[a-z_]+::[a-z]", _SQL)
