"""Mera-audit fix-3: cross-source dedup в _fetch_price_trend.

Проверяет что один объект на avito_imv + yandex_valuation с разными ext_item_id
не double-count'ится в месячной медиане (dedup всегда включён).
"""

from __future__ import annotations

import os
from typing import Any
from unittest.mock import MagicMock, patch

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

import pytest

from app.services.estimator import _fetch_price_trend


def _make_mock_db(source1_rows: list[dict], source2_rows: list[dict]) -> MagicMock:
    """Возвращает mock db: Source1 (houses_price_dynamics) → source1_rows,
    Source2 (house_placement_history) → source2_rows."""
    mock_db = MagicMock()

    def side_effect(*args: Any, **kwargs: Any) -> MagicMock:
        call_text = str(args[0].text) if args else ""
        result = MagicMock()
        if "houses_price_dynamics" in call_text:
            result.mappings.return_value.all.return_value = source1_rows
        else:
            result.mappings.return_value.all.return_value = source2_rows
        return result

    mock_db.execute.side_effect = side_effect
    return mock_db


# ---------------------------------------------------------------------------
# Fix-3: dedup enabled (default True)
# ---------------------------------------------------------------------------


def test_price_trend_dedup_sql_uses_distinct_on() -> None:
    """SQL-запрос к house_placement_history всегда содержит DISTINCT ON (dedup)."""
    mock_db = _make_mock_db([], [{"month": "2026-01", "ppm2": 150_000}])

    with patch("app.services.estimator.settings") as mock_settings:
        mock_settings.estimate_price_trend_max_age_months = 6

        _fetch_price_trend(mock_db, target_house_id=42, min_points=1)

    calls = mock_db.execute.call_args_list
    # Второй вызов — Source 2 (house_placement_history)
    assert len(calls) >= 2
    second_sql = str(calls[1].args[0].text) if calls[1].args else ""
    assert "DISTINCT ON" in second_sql.upper() or "distinct on" in second_sql.lower()


def test_price_trend_returns_result_with_dedup() -> None:
    """Функция корректно возвращает точки тренда (dedup включён)."""
    rows = [
        {"month": "2025-11", "ppm2": 148_000},
        {"month": "2025-12", "ppm2": 152_000},
        {"month": "2026-01", "ppm2": 155_000},
    ]
    mock_db = _make_mock_db([], rows)

    with patch("app.services.estimator.settings") as mock_settings:
        mock_settings.estimate_price_trend_max_age_months = 6

        result = _fetch_price_trend(mock_db, target_house_id=42, min_points=3)

    assert result is not None
    assert len(result) == 3
    assert result[0]["month"] == "2025-11"
    assert result[0]["ppm2"] == 148_000


def test_price_trend_source1_preferred_over_dedup_path() -> None:
    """Если Source1 (houses_price_dynamics) вернул ≥ min_points → Source2 не вызывается."""
    source1_rows = [
        {"month": "2025-11", "ppm2": 140_000},
        {"month": "2025-12", "ppm2": 145_000},
        {"month": "2026-01", "ppm2": 150_000},
    ]
    mock_db = _make_mock_db(source1_rows, [])

    with patch("app.services.estimator.settings") as mock_settings:
        mock_settings.estimate_price_trend_max_age_months = 6

        result = _fetch_price_trend(mock_db, target_house_id=42, min_points=3)

    # Source1 вернул 3 точки — Source2 не должен вызываться
    assert result is not None
    assert len(result) == 3
    calls = mock_db.execute.call_args_list
    # Ровно один вызов (Source1)
    assert len(calls) == 1


if __name__ == "__main__":  # pragma: no cover
    raise SystemExit(pytest.main([__file__, "-q"]))
