"""Tests for #794 СберИндекс time-adjustment helper — pure, no DB."""

from __future__ import annotations

import os
import sys
from datetime import date
from unittest.mock import MagicMock

# DATABASE_URL required by pydantic Settings before any app import.
os.environ.setdefault("DATABASE_URL", "postgresql+psycopg://test:test@localhost:5432/test")

# WeasyPrint stub — not installed in CI без GTK.
sys.modules.setdefault("weasyprint", MagicMock())

from app.services.estimator import (  # noqa: E402
    SBER_TIME_FACTOR_MAX,
    SBER_TIME_FACTOR_MIN,
    _sber_time_factor,
)


def test_empty_series_returns_one() -> None:
    assert _sber_time_factor({}, date(2026, 1, 1)) == 1.0


def test_deal_month_equals_latest_returns_one() -> None:
    series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0}
    assert _sber_time_factor(series, date(2026, 4, 1)) == 1.0


def test_deal_month_after_latest_returns_one() -> None:
    series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0}
    assert _sber_time_factor(series, date(2026, 6, 1)) == 1.0


def test_normal_factor_calculation() -> None:
    series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0}
    factor = _sber_time_factor(series, date(2026, 1, 1))
    expected = 100_000.0 / 95_000.0  # ≈ 1.0526
    assert abs(factor - expected) < 0.0001
    assert SBER_TIME_FACTOR_MIN <= factor <= SBER_TIME_FACTOR_MAX


def test_clamp_high() -> None:
    """Very old deal → factor would be >>1.6 → clamp to SBER_TIME_FACTOR_MAX."""
    series = {date(2020, 1, 1): 10_000.0, date(2026, 4, 1): 100_000.0}
    factor = _sber_time_factor(series, date(2020, 1, 1))
    assert factor == SBER_TIME_FACTOR_MAX


def test_clamp_low() -> None:
    """Series shows price drop → factor <<0.7 → clamp to SBER_TIME_FACTOR_MIN."""
    series = {date(2020, 1, 1): 200_000.0, date(2026, 4, 1): 50_000.0}
    factor = _sber_time_factor(series, date(2020, 1, 1))
    assert factor == SBER_TIME_FACTOR_MIN


def test_missing_month_uses_nearest_earlier() -> None:
    """deal_month=2026-02 not in series; nearest earlier is 2026-01."""
    series = {date(2026, 1, 1): 95_000.0, date(2026, 4, 1): 100_000.0}
    # Using 2026-01 as base: factor = 100000/95000
    factor_with_missing = _sber_time_factor(series, date(2026, 2, 1))
    factor_explicit = _sber_time_factor(series, date(2026, 1, 1))
    assert abs(factor_with_missing - factor_explicit) < 0.0001


def test_deal_older_than_series_uses_earliest() -> None:
    """Deal month before all series data → use earliest available month."""
    series = {date(2023, 1, 1): 80_000.0, date(2026, 4, 1): 100_000.0}
    # deal at 2020-01 is before series start → base = series[2023-01] = 80000
    factor = _sber_time_factor(series, date(2020, 1, 1))
    expected = min(100_000.0 / 80_000.0, SBER_TIME_FACTOR_MAX)
    assert abs(factor - expected) < 0.0001


def test_zero_base_returns_one() -> None:
    """Zero index value in series → guard → return 1.0."""
    series = {date(2026, 1, 1): 0.0, date(2026, 4, 1): 100_000.0}
    assert _sber_time_factor(series, date(2026, 1, 1)) == 1.0
