"""Unit-тесты для repair_state_normalizer (#621, #622).

Покрывают:
- normalize_repair_state(): все known raw → enum, idempotency, None-guard (#621).
- infer_repair_state_from_text(): русские фразы → enum, приоритет сигналов,
  unknown → None, None-guard (#622).
"""

import logging

import pytest

from app.services.scrapers.repair_state_normalizer import (
    infer_repair_state_from_text,
    normalize_repair_state,
)

# ── needs_repair ─────────────────────────────────────────────────────────────


@pytest.mark.parametrize("raw", ["required", "without", "no", "rough", "prefine"])
def test_needs_repair_values(raw: str) -> None:
    assert normalize_repair_state(raw) == "needs_repair"


def test_cian_camelcase_decoration_is_case_insensitive() -> None:
    """Cian detail отдаёт offer.decoration='preFine' (camelCase) — #1791."""
    assert normalize_repair_state("preFine") == "needs_repair"


# ── standard ─────────────────────────────────────────────────────────────────


def test_cosmetic_maps_to_standard() -> None:
    assert normalize_repair_state("cosmetic") == "standard"


# ── good ─────────────────────────────────────────────────────────────────────


@pytest.mark.parametrize("raw", ["euro", "fine"])
def test_good_values(raw: str) -> None:
    assert normalize_repair_state(raw) == "good"


# ── excellent ────────────────────────────────────────────────────────────────


@pytest.mark.parametrize("raw", ["designer", "design"])
def test_excellent_values(raw: str) -> None:
    assert normalize_repair_state(raw) == "excellent"


# ── None guard ───────────────────────────────────────────────────────────────


def test_none_returns_none() -> None:
    assert normalize_repair_state(None) is None


# ── idempotency ──────────────────────────────────────────────────────────────


@pytest.mark.parametrize("enum_val", ["needs_repair", "standard", "good", "excellent"])
def test_already_normalized_is_passthrough(enum_val: str) -> None:
    """Уже нормализованное значение возвращается as-is (idempotent при ре-обработке)."""
    assert normalize_repair_state(enum_val) == enum_val


# ── unknown value ────────────────────────────────────────────────────────────


def test_unknown_raw_returns_none(caplog: pytest.LogCaptureFixture) -> None:
    """Нераспознанное значение → None + WARNING в лог."""
    with caplog.at_level(
        logging.WARNING,
        logger="app.services.scrapers.repair_state_normalizer",
    ):
        result = normalize_repair_state("whitebox")
    assert result is None
    assert "whitebox" in caplog.text


# ═══════════════════════════════════════════════════════════════════════════════
# infer_repair_state_from_text() — извлечение из описания (#622)
# ═══════════════════════════════════════════════════════════════════════════════


# ── excellent ────────────────────────────────────────────────────────────────


@pytest.mark.parametrize(
    "text",
    [
        "Сделан дизайнерский ремонт с авторской мебелью",
        "Квартира с дизайнерской отделкой премиум-класса",
        "Премиальный ремонт от застройщика",
        "Эксклюзивный ремонт по индивидуальному проекту",
        "Авторский ремонт, всё новое",
    ],
)
def test_infer_excellent(text: str) -> None:
    assert infer_repair_state_from_text(text) == "excellent"


# ── good ─────────────────────────────────────────────────────────────────────


@pytest.mark.parametrize(
    "text",
    [
        "Свежий евроремонт, заезжай и живи",
        "Сделан евро-ремонт в 2024 году",
        "Современный ремонт, всё в отличном состоянии — ремонт в отличном",
        "Отличный ремонт, продаётся с мебелью",
        "Качественный ремонт от собственника",
    ],
)
def test_infer_good(text: str) -> None:
    assert infer_repair_state_from_text(text) == "good"


# ── needs_repair ─────────────────────────────────────────────────────────────


@pytest.mark.parametrize(
    "text",
    [
        "Квартира без отделки, под чистовую отделку",
        "Сдаётся без ремонта, черновая отделка",
        "Черновой ремонт, нужен ремонт",
        "Требует ремонта, торг уместен",
        "Требуется косметический ремонт",
        "Квартира под ремонт, цена снижена",
        "Предчистовая отделка от застройщика",
    ],
)
def test_infer_needs_repair(text: str) -> None:
    assert infer_repair_state_from_text(text) == "needs_repair"


# ── standard ─────────────────────────────────────────────────────────────────


@pytest.mark.parametrize(
    "text",
    [
        "Косметический ремонт, чисто и уютно",
        "Сделана косметическая отделка",
        "Обычный ремонт, всё работает",
        "Квартира в жилом состоянии",
        "Хорошее состояние, заезжай и живи",
    ],
)
def test_infer_standard(text: str) -> None:
    assert infer_repair_state_from_text(text) == "standard"


# ── приоритет сигналов (порядок excellent > good > needs_repair > standard) ───


def test_infer_excellent_beats_needs_repair() -> None:
    """Дизайнерский ремонт после черновой → excellent, не needs_repair."""
    text = "Была черновая отделка, теперь сделан дизайнерский ремонт"
    assert infer_repair_state_from_text(text) == "excellent"


def test_infer_good_beats_standard() -> None:
    """Евроремонт + косметический → good (сильнее)."""
    text = "Косметический ремонт обновлён до евроремонта"
    assert infer_repair_state_from_text(text) == "good"


# ── None / unknown guard ─────────────────────────────────────────────────────


def test_infer_none_returns_none() -> None:
    assert infer_repair_state_from_text(None) is None


def test_infer_empty_returns_none() -> None:
    assert infer_repair_state_from_text("") is None


def test_infer_unknown_text_returns_none() -> None:
    """Текст без repair-сигналов → None (не фабрикуем)."""
    text = "Светлая квартира рядом с метро, развитая инфраструктура, школа во дворе"
    assert infer_repair_state_from_text(text) is None
