"""Test all code snippets from docs/arbitrage.mdx.

Each snippet is wrapped in try/except and reports PASS/FAIL.
Snippets requiring network access, real exchange connections, or hz.run() are skipped.
"""

import horizon as hz

passed = 0
failed = 0
skipped = 0
results = []


def record(name, status, detail=""):
    global passed, failed, skipped
    if status == "PASS":
        passed += 1
    elif status == "FAIL":
        failed += 1
    else:
        skipped += 1
    tag = f"[{status}]"
    msg = f"  {tag:8s} {name}"
    if detail:
        msg += f" -- {detail}"
    print(msg)
    results.append((name, status, detail))


# ---------------------------------------------------------------------------
# Snippet 1: engine.execute_arbitrage() -- paper engine
# Doc lines 43-54
# ---------------------------------------------------------------------------
print("\n=== Snippet 1: engine.execute_arbitrage() (paper engine) ===")
try:
    # Paper engine with risk limits sufficient for the trade
    engine = hz.Engine(
        exchange_type="paper",
        risk_config=hz.RiskConfig(
            max_position_per_market=200.0,
            max_portfolio_notional=5000.0,
            max_order_size=100.0,
        ),
    )

    # For paper engine, execute_arbitrage submits buy+sell through risk pipeline.
    # Both legs go to the same paper exchange (valid for testing routing).
    buy_id, sell_id = engine.execute_arbitrage(
        market_id="will-btc-hit-100k",
        buy_exchange="paper",
        sell_exchange="paper",
        buy_price=0.48,
        sell_price=0.52,
        size=10.0,
        side=None,
        token_id=None,
        neg_risk=False,
    )
    assert isinstance(buy_id, str), f"Expected str, got {type(buy_id)}"
    assert isinstance(sell_id, str), f"Expected str, got {type(sell_id)}"
    print(f"  Buy: {buy_id}, Sell: {sell_id}")
    record("Snippet 1: engine.execute_arbitrage()", "PASS")
except Exception as e:
    record("Snippet 1: engine.execute_arbitrage()", "FAIL", str(e))

# ---------------------------------------------------------------------------
# Snippet 2: hz.arb_scanner() factory creation
# Doc lines 83-95
# ---------------------------------------------------------------------------
print("\n=== Snippet 2: hz.arb_scanner() factory ===")
try:
    scanner = hz.arb_scanner(
        market_id="will-btc-hit-100k",
        exchanges=["polymarket", "kalshi"],
        feed_map={
            "polymarket": "poly_feed",
            "kalshi": "kalshi_feed",
        },
        min_edge=0.01,
        max_size=50.0,
        fee_rates=None,
        auto_execute=False,
        cooldown=5.0,
    )
    assert callable(scanner), "Scanner should be callable"
    assert scanner.__name__ == "arb_scanner", f"Expected name 'arb_scanner', got '{scanner.__name__}'"
    record("Snippet 2: hz.arb_scanner() factory", "PASS")
except Exception as e:
    record("Snippet 2: hz.arb_scanner() factory", "FAIL", str(e))

# ---------------------------------------------------------------------------
# Snippet 3: hz.arb_sweep() one-shot
# Doc lines 118-133
# We use a paper engine. scan_arbitrage on paper with no feeds will return
# empty list, so arb_sweep returns None. We verify the call completes
# without error and returns None (no opportunity).
# ---------------------------------------------------------------------------
print("\n=== Snippet 3: hz.arb_sweep() one-shot ===")
try:
    engine = hz.Engine(
        exchange_type="paper",
        risk_config=hz.RiskConfig(
            max_position_per_market=200.0,
            max_portfolio_notional=5000.0,
            max_order_size=100.0,
        ),
    )

    result = hz.arb_sweep(
        engine=engine,
        market_id="will-btc-hit-100k",
        feed_map={
            "polymarket": "poly_feed",
            "kalshi": "kalshi_feed",
        },
        min_edge=0.01,
        max_size=50.0,
    )

    # With no feeds set up, scan_arbitrage should find nothing
    if result is None:
        print("  No arb found (expected with no live feeds)")
        record("Snippet 3: hz.arb_sweep() returns None (no feeds)", "PASS")
    else:
        print(f"  Found arb: buy on {result.buy_exchange} at {result.buy_price}")
        print(f"             sell on {result.sell_exchange} at {result.sell_price}")
        print(f"             edge: {result.net_edge:.4f}")
        record("Snippet 3: hz.arb_sweep() returned ArbResult", "PASS")
except Exception as e:
    record("Snippet 3: hz.arb_sweep()", "FAIL", str(e))

# ---------------------------------------------------------------------------
# Snippet 4: ArbResult dataclass construction
# Doc lines 144-157
# ---------------------------------------------------------------------------
print("\n=== Snippet 4: ArbResult dataclass ===")
try:
    result = hz.ArbResult(
        market_id="will-btc-hit-100k",
        buy_exchange="kalshi",
        sell_exchange="polymarket",
        buy_price=0.48,
        sell_price=0.52,
        size=10.0,
        raw_edge=0.04,
        net_edge=0.02,
        buy_order_id="order1",
        sell_order_id="order2",
        timestamp=1700000000.0,
    )
    assert result.market_id == "will-btc-hit-100k"
    assert result.buy_exchange == "kalshi"
    assert result.sell_exchange == "polymarket"
    assert abs(result.buy_price - 0.48) < 1e-9
    assert abs(result.sell_price - 0.52) < 1e-9
    assert abs(result.size - 10.0) < 1e-9
    assert abs(result.raw_edge - 0.04) < 1e-9
    assert abs(result.net_edge - 0.02) < 1e-9
    assert result.buy_order_id == "order1"
    assert result.sell_order_id == "order2"
    assert abs(result.timestamp - 1700000000.0) < 1e-9
    print(f"  ArbResult: {result}")
    record("Snippet 4: ArbResult dataclass", "PASS")
except Exception as e:
    record("Snippet 4: ArbResult dataclass", "FAIL", str(e))

# ---------------------------------------------------------------------------
# Snippet 5: Cross-Exchange Arb with Pipeline (uses hz.run + real exchanges)
# Doc lines 180-207
# SKIP: Requires real exchange credentials and hz.run()
# ---------------------------------------------------------------------------
print("\n=== Snippet 5: Cross-Exchange Arb with Pipeline ===")
record("Snippet 5: Cross-Exchange Arb with Pipeline", "SKIP", "requires hz.run() + real exchange credentials")

# ---------------------------------------------------------------------------
# Snippet 6: Manual Arbitrage Execution (real exchanges)
# Doc lines 213-232
# SKIP: Requires real exchange connections (polymarket, kalshi)
# ---------------------------------------------------------------------------
print("\n=== Snippet 6: Manual Arbitrage Execution ===")
record("Snippet 6: Manual Arbitrage Execution", "SKIP", "requires real exchange connections")

# ---------------------------------------------------------------------------
# Snippet 7: Combining Arb with Market Making (uses hz.run)
# Doc lines 239-259
# We can test the function definition part (arb_or_mm), but not hz.run().
# Test that the function can be defined and the arb_sweep + market_maker
# callables exist.
# ---------------------------------------------------------------------------
print("\n=== Snippet 7: Combining Arb with Market Making (definition only) ===")
try:
    def arb_or_mm(ctx):
        """Scan for arb, fall back to market making."""
        result = hz.arb_sweep(
            engine=ctx.params.get("engine"),
            market_id=ctx.market.id,
            feed_map={"polymarket": "poly", "kalshi": "kalshi"},
            min_edge=0.02,
        )
        if result:
            return []  # Arb executed, no quotes needed

        # No arb, do market making
        mm = hz.market_maker(feed_name="poly", size=5.0)
        return mm(ctx)

    assert callable(arb_or_mm), "arb_or_mm should be callable"
    assert arb_or_mm.__name__ == "arb_or_mm"
    # Verify the referenced functions exist
    assert callable(hz.arb_sweep)
    assert callable(hz.market_maker)
    record("Snippet 7: arb_or_mm function definition", "PASS")
except Exception as e:
    record("Snippet 7: arb_or_mm function definition", "FAIL", str(e))

# ---------------------------------------------------------------------------
# Summary
# ---------------------------------------------------------------------------
print("\n" + "=" * 60)
print("SUMMARY")
print("=" * 60)
print(f"  Total snippets: {passed + failed + skipped}")
print(f"  PASS:    {passed}")
print(f"  FAIL:    {failed}")
print(f"  SKIP:    {skipped}")
print("=" * 60)

if failed > 0:
    print("\nFailed tests:")
    for name, status, detail in results:
        if status == "FAIL":
            print(f"  - {name}: {detail}")

if skipped > 0:
    print("\nSkipped tests:")
    for name, status, detail in results:
        if status == "SKIP":
            print(f"  - {name}: {detail}")
