"""Tests для build_layout_tz_html — §4.2 «По предложению (без темпа продаж)».

Проверяют HTML-разметку ТЗ (наличие блоков, RU-микрокопию, форматирование ₽/м²)
БЕЗ WeasyPrint: `build_layout_tz_html` — PURE-функция (строит строку HTML), поэтому
эти тесты гоняются и на macOS/Windows, где native GTK/Pango отсутствуют (в отличие
от test_layout_tz_pdf.py, который зависит от write_pdf → native libs).

Ключевой сценарий: §4.2 блок рендерится, когда `supply_only_layouts` есть, и
graceful ОТСУТСТВУЕТ (без ошибок), когда список пуст (старые снапшоты / нет матча).
"""

import datetime as dt

from app.schemas.parcel import (
    BestLayoutsResponse,
    LayoutDataQuality,
    LayoutTzMixRow,
    LayoutTzRecommendation,
    SupplyOnlyLayoutRow,
    TopLayoutRow,
)
from app.services.exporters.layout_tz_pdf import build_layout_tz_html


def _base_response(supply_only: list[SupplyOnlyLayoutRow] | None = None) -> BestLayoutsResponse:
    return BestLayoutsResponse(
        top_layouts=[
            TopLayoutRow(
                rank=1,
                room_bucket="1",
                area_bin="25-40",
                signature="1__25-40",
                competitor_obj_ids=[1234],
                competitor_count=1,
                total_sold_in_window=67,
                velocity_per_month=8.4,
                avg_price_per_m2_rub=148000.0,
                avg_area_m2=38.5,
                supply_units_in_radius=312,
                sold_pct_of_supply=21.5,
                is_oversold=False,
            ),
        ],
        recommendation_for_tz=LayoutTzRecommendation(
            rationale_text="Test rationale текст",
            mix=[LayoutTzMixRow(room_bucket="1", pct=100, abs_units=100, avg_target_area_m2=38.5)],
            weighted_avg_price_per_m2_rub=152000.0,
            based_on_obj_count=5,
            based_on_total_deals=107,
            data_window_start=dt.date(2026, 2, 1),
            data_window_end=dt.date(2026, 5, 1),
        ),
        data_quality=LayoutDataQuality(
            objects_with_velocity_data=5,
            objects_total_in_radius=8,
            raw_objects_total=14,
            velocity_coverage_pct=62.5,
            confidence="medium",
        ),
        supply_only_layouts=supply_only or [],
    )


def _render(response: BestLayoutsResponse) -> str:
    return build_layout_tz_html(
        response,
        cad_num="66:41:0204016:10",
        radius_km=1.0,
        time_window="last_quarter",
    )


def test_supply_only_block_renders_when_present() -> None:
    """§4.2: блок «По предложению (без темпа продаж)» + строки supply_only_layouts."""
    resp = _base_response(
        [
            SupplyOnlyLayoutRow(
                project_name="ЖК Тестовый",
                room_bucket="2",
                area_bin="50-65",
                lots_count=17,
                median_price_m2=132500.0,
                median_area_m2=58.3,
            ),
        ]
    )
    html = _render(resp)
    # Заголовок + caveat про «без темпа продаж» / objective_lots.
    assert "По предложению (без темпа продаж)" in html
    assert "objective_lots" in html or "Объектив" in html
    # Данные строки: комплекс, тип, лоты, медиана ₽/м², ср. площадь.
    assert "ЖК Тестовый" in html
    assert "17" in html
    assert "132 500 ₽/м²" in html  # тыс-разделитель — неразрывный/обычный пробел
    assert "58.3 м²" in html


def test_supply_only_block_absent_when_empty() -> None:
    """Graceful: пустой supply_only_layouts (старый снапшот) → секции НЕТ, не падаем."""
    html = _render(_base_response([]))
    assert "По предложению (без темпа продаж)" not in html
    # Основной документ всё равно собран.
    assert "Техническое задание на проектирование" in html


def test_supply_only_null_price_renders_dash() -> None:
    """median_price_m2=None (цены не прошли price-sanity) → «—», без ошибок."""
    resp = _base_response(
        [
            SupplyOnlyLayoutRow(
                project_name="ЖК Без цен",
                room_bucket="studio",
                area_bin="<25",
                lots_count=4,
                median_price_m2=None,
                median_area_m2=None,
            ),
        ]
    )
    html = _render(resp)
    assert "По предложению (без темпа продаж)" in html
    assert "ЖК Без цен" in html
    assert "<td>—</td>" in html


def test_top_layouts_block_still_present() -> None:
    """§4.2-блок аддитивен: топ продаж конкурентов не потеснён."""
    html = _render(_base_response([]))
    assert "Топ планировок конкурентов по продажам" in html
    assert "Рекомендуемая структура квартирографии" in html
