"""
Tests for mev_protection.py - MEV Shield Analysis
"""

import asyncio
import json
import os
import sys

sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from app.mev_protection import (
    MevFactor,
    MevRiskLevel,
    MevShieldResult,
    _check_gas_price_risk,
    _check_historical_mev,
    _check_mempool_risk,
    _check_pool_liquidity,
    _check_slippage_risk,
    _check_timing_risk,
    analyze_transaction_risk,
    mev_shield_analysis,
)


async def test_mempool_risk() -> None:
    """Test mempool activity risk assessment."""
    print("🧪 test_mempool_risk")
    result = await _check_mempool_risk("ethereum")
    assert isinstance(result, MevFactor)
    assert 0.0 <= result.score <= 1.0
    assert result.name == "mempool_activity"
    print(f"  Score: {result.score:.2f} - {result.finding}")
    print(f"  Suggestion: {result.suggestion}")
    print("  ✅ PASS")


async def test_slippage_risk() -> None:
    """Test slippage tolerance assessment."""
    print("\n🧪 test_slippage_risk")

    # Low slippage (0.5%)
    low = await _check_slippage_risk(50)
    assert low.score <= 0.3
    print(f"  Low (0.5%): score={low.score:.2f} - {low.finding}")

    # Medium slippage (1%)
    med = await _check_slippage_risk(100)
    assert 0.3 <= med.score <= 0.7
    print(f"  Med (1.0%): score={med.score:.2f} - {med.finding}")

    # High slippage (3%+)
    high = await _check_slippage_risk(500)
    assert high.score >= 0.7
    print(f"  High (5%): score={high.score:.2f} - {high.finding}")

    print("  ✅ PASS")


async def test_gas_price_risk() -> None:
    """Test gas price risk assessment."""
    print("\n🧪 test_gas_price_risk")

    # Low slippage (0.5%)
    low = await _check_gas_price_risk(5.0)
    assert low.score <= 0.3
    print(f"  Low (5 gwei): score={low.score:.2f} - {low.finding}")

    med = await _check_gas_price_risk(25.0)
    assert 0.3 <= med.score <= 0.6
    print(f"  Med (25 gwei): score={med.score:.2f} - {med.finding}")

    high = await _check_gas_price_risk(75.0)
    assert high.score >= 0.6
    print(f"  High (75 gwei): score={high.score:.2f} - {high.finding}")

    print("  ✅ PASS")


async def test_timing_risk() -> None:
    """Test timing-based risk assessment."""
    print("\n🧪 test_timing_risk")
    result = await _check_timing_risk()
    assert isinstance(result, MevFactor)
    assert 0.0 <= result.score <= 1.0
    print(f"  Score: {result.score:.2f} - {result.finding}")
    print(f"  Suggestion: {result.suggestion}")
    print("  ✅ PASS")


async def test_historical_mev() -> None:
    """Test historical MEV check (fallback mode, no actual detector loaded)."""
    print("\n🧪 test_historical_mev (fallback - no real detector)")
    result = await _check_historical_mev("ethereum")
    assert isinstance(result, MevFactor)
    assert result.score > 0  # Should have default chain risk score
    print(f"  Score: {result.score:.2f} - {result.finding}")
    print("  ✅ PASS")


async def test_liquidity_risk() -> None:
    """Test pool liquidity assessment (no real pair - should return unknown)."""
    print("\n🧪 test_liquidity_risk (no pair address)")
    result = await _check_pool_liquidity(None, "ethereum")
    assert isinstance(result, MevFactor)
    assert result.name == "pool_liquidity"
    print(f"  Score: {result.score:.2f} - {result.finding}")
    print("  ✅ PASS")


async def test_full_analysis() -> None:
    """Test full MEV Shield analysis with default params."""
    print("\n🧪 test_full_analysis")
    result = await analyze_transaction_risk(
        chain="ethereum",
        slippage_bps=100,
        gas_price_gwei=15.0,
    )
    assert isinstance(result, MevShieldResult)
    assert isinstance(result.risk_level, MevRiskLevel)
    assert 0.0 <= result.overall_score <= 1.0
    assert len(result.factors) == 6
    assert len(result.protection_strategies) > 0
    assert result.estimated_loss_bps > 0

    print(f"  Risk Level: {result.risk_level.value.upper()}")
    print(f"  Overall Score: {result.overall_score:.2f}")
    print(f"  Est. Loss: {result.estimated_loss_bps} bps")

    for f in result.factors:
        print(f"    {f.name:25s} {f.score:.2f} - {f.finding}")

    print("  ✅ PASS")


async def test_full_high_risk() -> None:
    """Test full analysis with high-risk params."""
    print("\n🧪 test_full_high_risk")
    result = await analyze_transaction_risk(
        chain="ethereum",
        slippage_bps=500,  # 5% - reckless
        gas_price_gwei=200.0,  # Premium gas
    )
    assert result.risk_level in (MevRiskLevel.HIGH, MevRiskLevel.CRITICAL)
    assert len(result.protection_strategies) >= 2
    print(f"  Risk Level: {result.risk_level.value.upper()}")
    print(f"  Overall Score: {result.overall_score:.2f}")
    print("  ✅ PASS")


async def test_sync_wrapper() -> None:
    """Test the synchronous wrapper function."""
    print("\n🧪 test_sync_wrapper")
    result = mev_shield_analysis(
        chain="ethereum",
        slippage_bps=100,
        gas_price_gwei=10.0,
    )
    assert isinstance(result, dict)
    assert "risk_level" in result
    assert "factors" in result
    assert "protection_strategies" in result
    assert "estimated_loss_bps" in result
    print(f"  Risk Level: {result['risk_level']}")
    print(f"  Loss (bps): {result['estimated_loss_bps']}")
    print("  ✅ PASS")


async def test_result_to_dict() -> None:
    """Test serialization."""
    print("\n🧪 test_result_to_dict")
    result = await analyze_transaction_risk(
        chain="bsc",
        slippage_bps=200,
        gas_price_gwei=5.0,
    )
    d = result.to_dict()
    assert isinstance(d, dict)
    assert json.dumps(d)  # Must be JSON-serializable
    assert "factors" in d
    assert len(d["factors"]) == 6
    print(f"  JSON output: {json.dumps(d, indent=2)[:200]}...")
    print("  ✅ PASS")


async def main() -> bool:
    print("=" * 60)
    print("MEV Shield Analysis - Test Suite")
    print("=" * 60)

    tests = [
        test_mempool_risk,
        test_slippage_risk,
        test_gas_price_risk,
        test_timing_risk,
        test_historical_mev,
        test_liquidity_risk,
        test_full_analysis,
        test_full_high_risk,
        test_sync_wrapper,
        test_result_to_dict,
    ]

    passed = 0
    failed = 0

    for test_fn in tests:
        try:
            await test_fn()
            passed += 1
        except Exception as e:
            print(f"  ❌ FAIL: {e}")
            import traceback

            traceback.print_exc()
            failed += 1

    print(f"\n{'=' * 60}")
    print(f"Results: {passed} passed, {failed} failed")
    return failed == 0


if __name__ == "__main__":
    success = asyncio.run(main())
    sys.exit(0 if success else 1)
