"""
Test all Python code snippets from the exchanges documentation files.

Source files:
  - docs/exchanges/polymarket.mdx
  - docs/exchanges/kalshi.mdx
  - docs/exchanges/paper.mdx

For live exchange snippets: verify imports and construction only (no actual orders).
Print PASS/FAIL for each snippet.
"""

import sys
import traceback

results = []


def run_test(name, fn):
    """Run a test function and record PASS/FAIL."""
    try:
        fn()
        results.append((name, "PASS", None))
        print(f"PASS: {name}")
    except Exception as e:
        results.append((name, "FAIL", str(e)))
        print(f"FAIL: {name}")
        traceback.print_exc()
        print()


# =============================================================================
# POLYMARKET.MDX SNIPPETS
# =============================================================================

def test_polymarket_quick_setup():
    """
    Snippet from polymarket.mdx - Quick Setup (lines 11-23):
        hz.run(
            name="poly_mm",
            exchange=hz.Polymarket(
                private_key="0x...",
                api_key="...",
                api_secret="...",
                api_passphrase="...",
            ),
            mode="live",
            ...
        )
    We verify construction only (no hz.run call -- that would attempt live trading).
    """
    import horizon as hz
    poly = hz.Polymarket(
        private_key="0x0000000000000000000000000000000000000000000000000000000000000001",
        api_key="test_key",
        api_secret="test_secret",
        api_passphrase="test_pass",
    )
    assert poly.private_key is not None
    assert poly.api_key == "test_key"
    assert poly.api_secret == "test_secret"
    assert poly.api_passphrase == "test_pass"


def test_polymarket_private_key_only():
    """
    Snippet from polymarket.mdx - Credentials / Private key only (line 34):
        hz.Polymarket(private_key="0xYOUR_PRIVATE_KEY")
    """
    import horizon as hz
    poly = hz.Polymarket(private_key="0xYOUR_PRIVATE_KEY")
    assert poly.private_key == "0xYOUR_PRIVATE_KEY"
    assert poly.api_key is None or poly.api_key is not None  # may read from env


def test_polymarket_full_credentials():
    """
    Snippet from polymarket.mdx - Credentials / Full credentials (lines 43-48):
        hz.Polymarket(
            private_key="0x...",
            api_key="...",
            api_secret="...",
            api_passphrase="...",
        )
    """
    import horizon as hz
    poly = hz.Polymarket(
        private_key="0x...",
        api_key="...",
        api_secret="...",
        api_passphrase="...",
    )
    assert poly.private_key == "0x..."


def test_polymarket_env_vars():
    """
    Snippet from polymarket.mdx - Credentials / Environment variables (line 60):
        hz.Polymarket()  # reads from env
    """
    import os
    import horizon as hz
    # Clear env to ensure no accidental reads
    old = {}
    for k in ["POLYMARKET_PRIVATE_KEY", "POLYMARKET_API_KEY",
              "POLYMARKET_API_SECRET", "POLYMARKET_API_PASSPHRASE"]:
        old[k] = os.environ.pop(k, None)
    try:
        poly = hz.Polymarket()
        # With no env vars set, all should be None
        assert poly.private_key is None
        assert poly.api_key is None
    finally:
        for k, v in old.items():
            if v is not None:
                os.environ[k] = v


def test_polymarket_dataclass_definition():
    """
    Snippet from polymarket.mdx - Polymarket Configuration (lines 68-76):
        @dataclass
        class Polymarket:
            private_key: str | None = None
            clob_url: str = "https://clob.polymarket.com"
            gamma_url: str = "https://gamma-api.polymarket.com"
            api_key: str | None = None
            api_secret: str | None = None
            api_passphrase: str | None = None
    Verify the actual dataclass fields match.
    """
    import horizon as hz
    import dataclasses
    poly = hz.Polymarket()
    fields = {f.name for f in dataclasses.fields(poly)}
    expected = {"private_key", "clob_url", "gamma_url", "api_key", "api_secret", "api_passphrase"}
    assert expected.issubset(fields), f"Missing fields: {expected - fields}"
    # Check defaults
    poly2 = hz.Polymarket()
    assert poly2.clob_url == "https://clob.polymarket.com"
    assert poly2.gamma_url == "https://gamma-api.polymarket.com"


def test_polymarket_token_id_routing():
    """
    Snippet from polymarket.mdx - Token ID Routing (lines 102-111):
        market = hz.Market(
            id="will-btc-hit-100k",
            yes_token_id="123456789",
            no_token_id="987654321",
            condition_id="0x...",
            neg_risk=True,
        )
        market.token_id(Side.Yes)  # "123456789"
        market.token_id(Side.No)   # "987654321"
    """
    import horizon as hz
    market = hz.Market(
        id="will-btc-hit-100k",
        yes_token_id="123456789",
        no_token_id="987654321",
        condition_id="0x...",
        neg_risk=True,
    )
    assert market.token_id(hz.Side.Yes) == "123456789"
    assert market.token_id(hz.Side.No) == "987654321"


# =============================================================================
# KALSHI.MDX SNIPPETS
# =============================================================================

def test_kalshi_quick_setup():
    """
    Snippet from kalshi.mdx - Quick Setup (lines 12-17):
        hz.run(
            name="kalshi_mm",
            exchange=hz.Kalshi(api_key="..."),
            mode="live",
            ...
        )
    Verify construction only.
    """
    import horizon as hz
    k = hz.Kalshi(api_key="test_api_key")
    assert k.api_key == "test_api_key"


def test_kalshi_api_key():
    """
    Snippet from kalshi.mdx - Credentials / API key (line 24):
        hz.Kalshi(api_key="your_api_key")
    """
    import horizon as hz
    k = hz.Kalshi(api_key="your_api_key")
    assert k.api_key == "your_api_key"


def test_kalshi_email_password():
    """
    Snippet from kalshi.mdx - Credentials / Email/password (lines 29-30):
        hz.Kalshi(email="you@example.com", password="...")
    """
    import horizon as hz
    k = hz.Kalshi(email="you@example.com", password="secret")
    assert k.email == "you@example.com"
    assert k.password == "secret"


def test_kalshi_env_vars():
    """
    Snippet from kalshi.mdx - Credentials / Environment variables (line 42):
        hz.Kalshi()  # reads from env
    """
    import os
    import horizon as hz
    old = {}
    for key in ["KALSHI_API_KEY", "KALSHI_EMAIL", "KALSHI_PASSWORD", "KALSHI_API_URL"]:
        old[key] = os.environ.pop(key, None)
    try:
        k = hz.Kalshi()
        assert k.api_key is None
        assert k.email is None
    finally:
        for key, v in old.items():
            if v is not None:
                os.environ[key] = v


def test_kalshi_dataclass_definition():
    """
    Snippet from kalshi.mdx - Kalshi Configuration (lines 50-56):
        @dataclass
        class Kalshi:
            email: str | None = None
            password: str | None = None
            api_key: str | None = None
            api_url: str = "https://trading-api.kalshi.com/trade-api/v2"
    """
    import horizon as hz
    import dataclasses
    k = hz.Kalshi()
    fields = {f.name for f in dataclasses.fields(k)}
    expected = {"email", "password", "api_key", "api_url"}
    assert expected.issubset(fields), f"Missing fields: {expected - fields}"
    assert k.api_url == "https://trading-api.kalshi.com/trade-api/v2"


def test_kalshi_demo_environment():
    """
    Snippet from kalshi.mdx - Demo Environment (lines 70-73):
        hz.Kalshi(
            api_key="...",
            api_url="https://demo-api.kalshi.co/trade-api/v2",
        )
    """
    import horizon as hz
    k = hz.Kalshi(
        api_key="test_key",
        api_url="https://demo-api.kalshi.co/trade-api/v2",
    )
    assert k.api_url == "https://demo-api.kalshi.co/trade-api/v2"
    assert k.api_key == "test_key"


def test_kalshi_market_ticker():
    """
    Snippet from kalshi.mdx - Ticker Mapping (lines 92-96):
        market = hz.Market(
            id="btc-100k",
            ticker="KXBTC-25FEB16",
            exchange="kalshi",
        )
    """
    import horizon as hz
    market = hz.Market(
        id="btc-100k",
        ticker="KXBTC-25FEB16",
        exchange="kalshi",
    )
    assert market.id == "btc-100k"
    assert market.ticker == "KXBTC-25FEB16"
    assert market.exchange == "kalshi"


# =============================================================================
# PAPER.MDX SNIPPETS
# =============================================================================

def test_paper_default_usage():
    """
    Snippet from paper.mdx - Usage (lines 12-18, implicit):
        Paper is the default, just omit exchange.
    We test hz.run is callable and Engine() defaults to paper.
    """
    import horizon as hz
    engine = hz.Engine()
    # Default engine should be paper mode
    assert engine is not None


def test_paper_explicit_engine():
    """
    Snippet from paper.mdx - Usage (lines 24-26):
        engine = Engine()  # Default is paper
        engine = Engine(paper_fee_rate=0.001)  # Custom fee rate
        engine = Engine(paper_partial_fill_ratio=0.5)  # 50% partial fills
    """
    import horizon as hz
    engine1 = hz.Engine()
    engine2 = hz.Engine(paper_fee_rate=0.001)
    engine3 = hz.Engine(paper_partial_fill_ratio=0.5)
    assert engine1 is not None
    assert engine2 is not None
    assert engine3 is not None


def test_paper_flat_fee():
    """
    Snippet from paper.mdx - Maker/taker fees (line 59):
        engine = Engine(paper_fee_rate=0.001)
    """
    import horizon as hz
    engine = hz.Engine(paper_fee_rate=0.001)
    assert engine is not None


def test_paper_split_maker_taker_fees():
    """
    Snippet from paper.mdx - Maker/taker fees (lines 62-65):
        engine = Engine(
            paper_maker_fee_rate=0.0002,  # 2 bps for makers
            paper_taker_fee_rate=0.002,   # 20 bps for takers
        )
    """
    import horizon as hz
    engine = hz.Engine(
        paper_maker_fee_rate=0.0002,
        paper_taker_fee_rate=0.002,
    )
    assert engine is not None


def test_paper_override_one_side():
    """
    Snippet from paper.mdx - Maker/taker fees (line 68):
        engine = Engine(paper_fee_rate=0.001, paper_taker_fee_rate=0.003)
    """
    import horizon as hz
    engine = hz.Engine(paper_fee_rate=0.001, paper_taker_fee_rate=0.003)
    assert engine is not None


def test_paper_recent_fills_is_maker():
    """
    Snippet from paper.mdx - Maker/taker fees (lines 74-77):
        fills = engine.recent_fills()
        for f in fills:
            print(f"{f.fill_id}: {'maker' if f.is_maker else 'taker'} fee={f.fee:.4f}")
    Verify recent_fills() method exists and returns iterable (no fills yet).
    """
    import horizon as hz
    engine = hz.Engine()
    fills = engine.recent_fills()
    assert isinstance(fills, list)
    for f in fills:
        # Verify is_maker and fee attributes exist
        _ = f.fill_id
        _ = f.is_maker
        _ = f.fee


def test_paper_partial_fill_ratio():
    """
    Snippet from paper.mdx - Partial fills (line 90):
        engine = Engine(paper_partial_fill_ratio=0.5)
    """
    import horizon as hz
    engine = hz.Engine(paper_partial_fill_ratio=0.5)
    assert engine is not None


# =============================================================================
# Run all tests
# =============================================================================

if __name__ == "__main__":
    tests = [
        # Polymarket
        ("polymarket.mdx: Quick Setup construction", test_polymarket_quick_setup),
        ("polymarket.mdx: Private key only", test_polymarket_private_key_only),
        ("polymarket.mdx: Full credentials", test_polymarket_full_credentials),
        ("polymarket.mdx: Environment variables", test_polymarket_env_vars),
        ("polymarket.mdx: Dataclass definition", test_polymarket_dataclass_definition),
        ("polymarket.mdx: Token ID routing", test_polymarket_token_id_routing),
        # Kalshi
        ("kalshi.mdx: Quick Setup construction", test_kalshi_quick_setup),
        ("kalshi.mdx: API key credential", test_kalshi_api_key),
        ("kalshi.mdx: Email/password credential", test_kalshi_email_password),
        ("kalshi.mdx: Environment variables", test_kalshi_env_vars),
        ("kalshi.mdx: Dataclass definition", test_kalshi_dataclass_definition),
        ("kalshi.mdx: Demo environment", test_kalshi_demo_environment),
        ("kalshi.mdx: Market ticker", test_kalshi_market_ticker),
        # Paper
        ("paper.mdx: Default engine usage", test_paper_default_usage),
        ("paper.mdx: Explicit engine construction", test_paper_explicit_engine),
        ("paper.mdx: Flat fee rate", test_paper_flat_fee),
        ("paper.mdx: Split maker/taker fees", test_paper_split_maker_taker_fees),
        ("paper.mdx: Override one fee side", test_paper_override_one_side),
        ("paper.mdx: recent_fills() + is_maker/fee attrs", test_paper_recent_fills_is_maker),
        ("paper.mdx: Partial fill ratio", test_paper_partial_fill_ratio),
    ]

    print("=" * 70)
    print("Exchange Docs Snippet Tests")
    print("=" * 70)
    print()

    for name, fn in tests:
        run_test(name, fn)

    print()
    print("=" * 70)
    passed = sum(1 for _, status, _ in results if status == "PASS")
    failed = sum(1 for _, status, _ in results if status == "FAIL")
    print(f"Results: {passed} PASS, {failed} FAIL out of {len(results)} total")
    print("=" * 70)

    if failed > 0:
        print()
        print("FAILED TESTS:")
        for name, status, err in results:
            if status == "FAIL":
                print(f"  - {name}: {err}")

    sys.exit(1 if failed > 0 else 0)
