"""Tests for marketplace reputation score (Phase 5, issue 290)."""

from __future__ import annotations

from datetime import datetime, timedelta, timezone

import pytest

from llmhosts.marketplace.reputation import (
    STALE_SECONDS,
    compute_reputation_score,
    reputation_score_from_node,
)


@pytest.mark.unit
def test_score_in_range() -> None:
    """Score is always 0-100."""
    now = datetime.now(timezone.utc)
    recent = now - timedelta(seconds=60)
    assert 0 <= compute_reputation_score("online", 50, recent) <= 100
    assert 0 <= compute_reputation_score("offline", None, now - timedelta(days=1)) <= 100


@pytest.mark.unit
def test_online_recent_low_latency_100() -> None:
    """Online + recent + latency < 100ms => 100."""
    recent = datetime.now(timezone.utc) - timedelta(seconds=60)
    assert compute_reputation_score("online", 50, recent) == 100
    assert compute_reputation_score("online", 99, recent) == 100


@pytest.mark.unit
def test_online_recent_medium_latency_85() -> None:
    """Online + recent + 100 <= latency < 500 => 85."""
    recent = datetime.now(timezone.utc) - timedelta(seconds=60)
    assert compute_reputation_score("online", 100, recent) == 85
    assert compute_reputation_score("online", 499, recent) == 85


@pytest.mark.unit
def test_online_recent_high_latency_75() -> None:
    """Online + recent + latency >= 500 => 75."""
    recent = datetime.now(timezone.utc) - timedelta(seconds=60)
    assert compute_reputation_score("online", 500, recent) == 75
    assert compute_reputation_score("online", 2000, recent) == 75


@pytest.mark.unit
def test_offline_reduces_score() -> None:
    """Offline removes online bonus; max 75 from latency only."""
    recent = datetime.now(timezone.utc) - timedelta(seconds=60)
    assert compute_reputation_score("offline", 50, recent) == 75
    assert compute_reputation_score("degraded", 50, recent) == 75


@pytest.mark.unit
def test_stale_last_seen_reduces_score() -> None:
    """Stale last_seen removes online bonus."""
    stale = datetime.now(timezone.utc) - timedelta(seconds=STALE_SECONDS + 60)
    assert compute_reputation_score("online", 50, stale) == 75
    assert compute_reputation_score("online", 200, stale) == 60


@pytest.mark.unit
def test_offline_no_latency_base_50() -> None:
    """Offline and no latency => base 50."""
    old = datetime.now(timezone.utc) - timedelta(days=1)
    assert compute_reputation_score("offline", None, old) == 50
    assert compute_reputation_score("offline", None, None) == 50


@pytest.mark.unit
def test_last_seen_iso_string() -> None:
    """last_seen as ISO string is parsed and used for staleness."""
    recent = datetime.now(timezone.utc) - timedelta(seconds=60)
    stale = datetime.now(timezone.utc) - timedelta(seconds=STALE_SECONDS + 60)
    assert compute_reputation_score("online", 50, recent.isoformat()) == 100
    assert compute_reputation_score("online", 50, stale.isoformat()) == 75


@pytest.mark.unit
def test_reputation_score_from_node() -> None:
    """reputation_score_from_node computes from node dict."""
    recent = (datetime.now(timezone.utc) - timedelta(seconds=60)).isoformat()
    node = {"status": "online", "latency_ms": 80, "last_seen": recent}
    assert reputation_score_from_node(node) == 100
    node_off = {"status": "offline", "latency_ms": None, "last_seen": recent}
    assert reputation_score_from_node(node_off) == 50
