"""Tests for the Reputation Engine."""
import pytest
from swarmpay.reputation import ReputationEngine, ReputationConfig, AgentReputation

WALLET_A = "0x1111111111111111111111111111111111111111"
WALLET_B = "0x2222222222222222222222222222222222222222"
WALLET_C = "0x3333333333333333333333333333333333333333"


@pytest.fixture
def engine(tmp_path):
    return ReputationEngine(storage_path=str(tmp_path / "reputation.json"))


# ── Default Score ───────────────────────────────────────────

def test_default_score_is_3(engine):
    assert engine.get_score(WALLET_A) == 3.0


def test_new_agent_reputation(engine):
    rep = engine.get_reputation(WALLET_A)
    assert rep.wallet == WALLET_A
    assert rep.score == 3.0
    assert rep.total_deliveries == 0


# ── Score After Events ──────────────────────────────────────

def test_score_after_success(engine):
    engine.record_success(WALLET_A, response_time_seconds=5.0)
    score = engine.get_score(WALLET_A)
    assert score > 3.0


def test_score_after_failure(engine):
    engine.record_failure(WALLET_A)
    score = engine.get_score(WALLET_A)
    assert score < 3.0


def test_score_after_dispute(engine):
    engine.record_success(WALLET_A)  # 1 delivery
    engine.record_dispute(WALLET_A)  # 1 dispute
    score = engine.get_score(WALLET_A)
    # Dispute should lower score
    assert score < 5.0


def test_perfect_record(engine):
    for _ in range(10):
        engine.record_success(WALLET_A, response_time_seconds=2.0)
    score = engine.get_score(WALLET_A)
    assert score >= 4.5  # Should be near 5.0


def test_all_failures(engine):
    for _ in range(10):
        engine.record_failure(WALLET_A)
    score = engine.get_score(WALLET_A)
    assert score <= 2.5  # Low but response time default adds some


def test_score_bounds(engine):
    for _ in range(100):
        engine.record_success(WALLET_A, response_time_seconds=1.0)
    assert engine.get_score(WALLET_A) <= 5.0
    assert engine.get_score(WALLET_A) >= 0.0


# ── Response Time ───────────────────────────────────────────

def test_response_time_tracked(engine):
    engine.record_success(WALLET_A, response_time_seconds=10.0)
    engine.record_success(WALLET_A, response_time_seconds=20.0)
    rep = engine.get_reputation(WALLET_A)
    assert rep.avg_response_time_seconds == 15.0


# ── find_best ───────────────────────────────────────────────

def test_find_best_empty_list(engine):
    assert engine.find_best([]) is None


def test_find_best_single_provider(engine):
    providers = [{"wallet": WALLET_A, "price_usd": 1.0}]
    best = engine.find_best(providers)
    assert best["wallet"] == WALLET_A


def test_find_best_price_only(engine):
    providers = [
        {"wallet": WALLET_A, "price_usd": 5.0},
        {"wallet": WALLET_B, "price_usd": 1.0},
    ]
    best = engine.find_best(providers, reputation_factor=0.0)
    assert best["wallet"] == WALLET_B  # cheapest


def test_find_best_reputation_only(engine):
    # Give WALLET_A high reputation
    for _ in range(10):
        engine.record_success(WALLET_A, response_time_seconds=2.0)
    # WALLET_B stays at default 3.0
    providers = [
        {"wallet": WALLET_A, "price_usd": 10.0},  # expensive but good rep
        {"wallet": WALLET_B, "price_usd": 1.0},   # cheap but default rep
    ]
    best = engine.find_best(providers, reputation_factor=1.0)
    assert best["wallet"] == WALLET_A  # best reputation wins


def test_find_best_blended(engine):
    # Give WALLET_A high reputation
    for _ in range(10):
        engine.record_success(WALLET_A, response_time_seconds=2.0)
    providers = [
        {"wallet": WALLET_A, "price_usd": 2.0},
        {"wallet": WALLET_B, "price_usd": 1.0},
    ]
    # With moderate factor, good rep + reasonable price should win
    best = engine.find_best(providers, reputation_factor=0.5)
    assert best is not None


# ── Persistence ─────────────────────────────────────────────

def test_reputation_persistence(tmp_path):
    path = str(tmp_path / "rep.json")
    engine1 = ReputationEngine(storage_path=path)
    engine1.record_success(WALLET_A, response_time_seconds=5.0)
    score1 = engine1.get_score(WALLET_A)

    # Reload
    engine2 = ReputationEngine(storage_path=path)
    score2 = engine2.get_score(WALLET_A)
    assert score1 == score2


def test_independent_agent_scores(engine):
    engine.record_success(WALLET_A)
    engine.record_failure(WALLET_B)
    assert engine.get_score(WALLET_A) > engine.get_score(WALLET_B)
