"""Generative Design — Stage 1c PDF export via WeasyPrint.

Renders a one-page summary of the three concept variants — a ТЭП table and a
financial table — into a PDF. This is the *concept* summary, distinct from Site
Finder's ``app.services.exporters.report_pdf`` (advisory site report).

WeasyPrint is imported *lazily inside the function* (mirrors the repo's
``report_pdf`` / ``snapshot_pdf`` house-style): it is a heavy native dependency, so
importing this module must never fail even on a dev box without the system libs.

All dynamic strings are passed through ``html.escape`` (defence-in-depth: variant
strategy names are from a fixed Literal, but treat rendered text as untrusted).
Returns ``bytes`` ready for an HTTP response / file write. Deterministic, no DB /
no network.
"""

from __future__ import annotations

import html
import logging
from collections.abc import Sequence

from app.schemas.concept import ConceptVariant, FinancialModel

logger = logging.getLogger(__name__)

# RU-подписи стратегий (ключ — Literal из контракта).
_STRATEGY_LABELS: dict[str, str] = {
    "max_area": "Максимум площади",
    "max_insolation": "Максимум инсоляции",
    "balanced": "Баланс",
}

_DASH = "—"

# Минимальный CSS для печати (А4, читаемые таблицы). Inline — без внешних ресурсов.
_CSS = """
@page { size: A4 landscape; margin: 18mm; }
body { font-family: "DejaVu Sans", Arial, sans-serif; font-size: 11px; color: #1a1a1a; }
h1 { font-size: 18px; margin: 0 0 4px; }
.sub { color: #666; font-size: 10px; margin: 0 0 14px; }
table { border-collapse: collapse; width: 100%; margin-bottom: 18px; }
th, td { border: 1px solid #ccc; padding: 6px 8px; text-align: right; }
th.row, td.row { text-align: left; font-weight: 600; background: #f5f5f5; }
caption { text-align: left; font-weight: 700; font-size: 13px; margin-bottom: 6px; }
thead th { background: #ececec; }
"""

_TITLE = "Концепции застройки — сводка вариантов"
_SUBTITLE = "Generative Design · Stage 1c · детерминированный расчёт ТЭП, финмодели и DCF"


def _fmt_int(value: float | int) -> str:
    """Целое с разделителями тысяч (узкий пробел) для читаемости."""
    return f"{round(value):,}".replace(",", " ")


def _fmt_money(value: float) -> str:
    """Деньги в млн руб (1 знак) — итоговые таблицы читаются в млн."""
    return f"{value / 1_000_000:,.1f}".replace(",", " ")


def _strategy_label(strategy: str) -> str:
    return _STRATEGY_LABELS.get(strategy, strategy)


def _teap_table(variants: Sequence[ConceptVariant]) -> str:
    """HTML-таблица ТЭП по всем вариантам (строки — показатели, колонки — стратегии)."""
    headers = "".join(f"<th>{html.escape(_strategy_label(v.strategy))}</th>" for v in variants)
    rows: list[tuple[str, list[str]]] = [
        ("Пятно застройки, кв.м", [_fmt_int(v.teap.built_area_sqm) for v in variants]),
        ("Общая площадь (GFA), кв.м", [_fmt_int(v.teap.total_floor_area_sqm) for v in variants]),
        ("Жилая площадь, кв.м", [_fmt_int(v.teap.residential_area_sqm) for v in variants]),
        ("Квартир, шт", [_fmt_int(v.teap.apartments_count) for v in variants]),
        ("Плотность (FAR)", [f"{v.teap.density:.2f}" for v in variants]),
        ("Машиномест", [_fmt_int(v.teap.parking_spaces) for v in variants]),
    ]
    body = "".join(
        "<tr><td class='row'>"
        + html.escape(label)
        + "</td>"
        + "".join(f"<td>{html.escape(cell)}</td>" for cell in cells)
        + "</tr>"
        for label, cells in rows
    )
    return (
        "<table><caption>Технико-экономические показатели</caption>"
        f"<thead><tr><th class='row'>Показатель</th>{headers}</tr></thead>"
        f"<tbody>{body}</tbody></table>"
    )


def _fmt_pbp(value: float | None) -> str:
    """Срок окупаемости — мес (1 знак), либо «не окупается»."""
    if value is None:
        return "не окупается"
    return f"{value:.1f} мес"


def _fmt_irr(financial: FinancialModel) -> str:
    """IRR в % с пометкой «оценочный», если это proxy (вырожденный поток)."""
    pct = f"{financial.irr * 100:.1f}%"
    return f"{pct} (оценочный)" if financial.irr_is_proxy else pct


def _financial_table(variants: Sequence[ConceptVariant]) -> str:
    """HTML-таблица финмодели (деньги в млн руб; полный каскад + БДР + DCF)."""
    headers = "".join(f"<th>{html.escape(_strategy_label(v.strategy))}</th>" for v in variants)
    rows: list[tuple[str, list[str]]] = [
        (
            "Выручка — жильё, млн руб",
            [_fmt_money(v.financial.revenue_residential_rub) for v in variants],
        ),
        (
            "Выручка — паркинг, млн руб",
            [_fmt_money(v.financial.revenue_parking_rub) for v in variants],
        ),
        (
            "Выручка — нежилое (1-й этаж), млн руб",
            [_fmt_money(v.financial.revenue_office_rub) for v in variants],
        ),
        ("Выручка (GDV), млн руб", [_fmt_money(v.financial.revenue_rub) for v in variants]),
        ("СМР, млн руб", [_fmt_money(v.financial.construction_rub) for v in variants]),
        ("ПИР, млн руб", [_fmt_money(v.financial.pir_rub) for v in variants]),
        ("Сети (ТУ), млн руб", [_fmt_money(v.financial.networks_rub) for v in variants]),
        (
            "Услуги заказчика, млн руб",
            [_fmt_money(v.financial.developer_services_rub) for v in variants],
        ),
        ("Резерв, млн руб", [_fmt_money(v.financial.contingency_rub) for v in variants]),
        ("Маркетинг + риэлтор, млн руб", [_fmt_money(v.financial.marketing_rub) for v in variants]),
        ("Земля, млн руб", [_fmt_money(v.financial.land_rub) for v in variants]),
        ("Итого затраты, млн руб", [_fmt_money(v.financial.cost_rub) for v in variants]),
        ("Валовая маржа, млн руб", [_fmt_money(v.financial.gross_margin_rub) for v in variants]),
        (
            "НДС (нежилое: паркинг + коммерция), млн руб",
            [_fmt_money(v.financial.vat_rub) for v in variants],
        ),
        (
            "Прибыль до налога, млн руб",
            [_fmt_money(v.financial.profit_before_tax_rub) for v in variants],
        ),
        ("Налог на прибыль, млн руб", [_fmt_money(v.financial.profit_tax_rub) for v in variants]),
        ("Чистая прибыль, млн руб", [_fmt_money(v.financial.net_profit_rub) for v in variants]),
        ("ROI (на затраты)", [f"{v.financial.roi * 100:.1f}%" for v in variants]),
        ("Чистая маржа (на выручку)", [f"{v.financial.margin_pct * 100:.1f}%" for v in variants]),
        ("NPV (DCF), млн руб", [_fmt_money(v.financial.npv_rub) for v in variants]),
        ("IRR (DCF, годовой)", [_fmt_irr(v.financial) for v in variants]),
        ("Окупаемость (PBP)", [_fmt_pbp(v.financial.payback_months) for v in variants]),
    ]
    body = "".join(
        "<tr><td class='row'>"
        + html.escape(label)
        + "</td>"
        + "".join(f"<td>{html.escape(cell)}</td>" for cell in cells)
        + "</tr>"
        for label, cells in rows
    )
    return (
        "<table><caption>Финансовая модель (упрощённая)</caption>"
        f"<thead><tr><th class='row'>Показатель</th>{headers}</tr></thead>"
        f"<tbody>{body}</tbody></table>"
    )


def _build_html(variants: Sequence[ConceptVariant]) -> str:
    if not variants:
        return (
            f"<html><head><meta charset='utf-8'><style>{_CSS}</style></head>"
            f"<body><h1>{html.escape(_TITLE)}</h1>"
            f"<p class='sub'>{html.escape(_SUBTITLE)}</p>"
            f"<p>{_DASH} нет вариантов для отображения</p></body></html>"
        )
    disc_pct = f"{variants[0].financial.discount_rate_used * 100:.0f}%"
    return (
        f"<html><head><meta charset='utf-8'><style>{_CSS}</style></head><body>"
        f"<h1>{html.escape(_TITLE)}</h1>"
        f"<p class='sub'>{html.escape(_SUBTITLE)}</p>"
        f"{_teap_table(variants)}"
        f"{_financial_table(variants)}"
        "<p class='sub'>NPV / IRR / PBP рассчитаны помесячным DCF по ТИПОВОМУ графику фаз "
        f"(ПИР 6 мес → СМР по типу застройки → распродажа 30 мес, дисконт {disc_pct} годовых). "
        "График фаз и темп продаж — типовые допущения, НЕ график конкретного проекта; "
        "точность метрик зависит от реального графика. Где IRR помечен «оценочный» — поток "
        "вырожденный (нет смены знака), показан аннуализированный ROI вместо DCF-IRR. "
        "НДС — реализация жилья и услуги застройщика по ДДУ освобождены (ст. 149 НК РФ), "
        "входной НДС по СМР встроен в себестоимость; НДС начисляется на нежилые части — "
        "машиноместа и коммерцию/офисы 1-го этажа (встроенный НДС в добавленной стоимости "
        "каждой части). Налог на прибыль — 25% (с 2025). Цены и себестоимость — рыночные "
        "ориентиры. Коммерция/офисы 1-го этажа учтены по нормативной доле от общей площади "
        "и продаются с умеренной наценкой к цене жилья того же класса; себестоимость СМР "
        "нежилого — по той же ставке, что и жильё (отдельной строки затрат нет, повторного "
        "учёта в затратах нет).</p>"
        "</body></html>"
    )


def export_concept_pdf(variants: Sequence[ConceptVariant]) -> bytes:
    """Свести варианты в PDF-сводку (ТЭП + финмодель). Возвращает bytes (PDF).

    Graceful: пустой список вариантов рендерит страницу-заглушку, экспорт не падает.
    WeasyPrint импортируется лениво (тяжёлая нативная зависимость).
    """
    # Лениво: импорт WeasyPrint не должен падать при импорте модуля
    # (тяжёлая нативная зависимость; зеркало report_pdf/snapshot_pdf).
    from weasyprint import HTML

    document = _build_html(variants)
    # write_pdf(target=None) возвращает bytes; weasyprint без stubs -> явная коэрция.
    rendered = HTML(string=document).write_pdf()
    pdf_bytes: bytes = bytes(rendered) if rendered is not None else b""
    logger.info("PDF export: variants=%d bytes=%d", len(variants), len(pdf_bytes))
    return pdf_bytes


__all__ = ["export_concept_pdf"]
