# Issue #96: Quick REST API pagination test
# Tests Binance /api/v3/aggTrades pagination behavior:
#   - How many trades per request (max 1000)?
#   - Does startTime pagination produce contiguous agg_trade_ids?
#   - What's the throughput (requests/sec, trades/sec)?
#   - Can we use fromId instead of startTime for faster pagination?

import time

import requests

SYMBOL = "BTCUSDT"
BASE_URL = "https://api.binance.com/api/v3/aggTrades"

def test_single_request():
    """Test a single request to understand the response format."""
    print("=== TEST 1: Single request (latest 1000 trades) ===")
    resp = requests.get(BASE_URL, params={"symbol": SYMBOL, "limit": 1000}, timeout=10)
    trades = resp.json()
    print(f"  Status: {resp.status_code}")
    print(f"  Trades returned: {len(trades)}")
    if trades:
        first = trades[0]
        last = trades[-1]
        print(f"  First: id={first['a']}, T={first['T']}, p={first['p']}")
        print(f"  Last:  id={last['a']}, T={last['T']}, p={last['p']}")
        print(f"  ID range: {last['a'] - first['a']} (expect ~999)")
        print(f"  Time span: {(last['T'] - first['T'])/1000:.1f} sec")

        # Check contiguity
        gaps = 0
        for i in range(1, len(trades)):
            if trades[i]["a"] != trades[i-1]["a"] + 1:
                gaps += 1
                if gaps <= 3:
                    print(f"    Gap: id {trades[i-1]['a']} → {trades[i]['a']} (delta={trades[i]['a']-trades[i-1]['a']})")
        print(f"  Internal ID gaps: {gaps}")
    return trades


def test_starttime_pagination(n_pages=5):
    """Test startTime-based pagination (current Rust implementation)."""
    print(f"\n=== TEST 2: startTime pagination ({n_pages} pages) ===")

    # Start from 1 hour ago
    start_ms = int(time.time() * 1000) - 3600_000
    end_ms = int(time.time() * 1000)
    current_start = start_ms
    total_trades = 0
    all_ids = []
    page_times = []

    for page in range(n_pages):
        t0 = time.monotonic()
        resp = requests.get(BASE_URL, params={
            "symbol": SYMBOL,
            "startTime": str(current_start),
            "endTime": str(end_ms),
            "limit": "1000",
        }, timeout=10)
        elapsed = time.monotonic() - t0
        page_times.append(elapsed)

        batch = resp.json()
        if not batch:
            print(f"  Page {page}: empty (exhausted)")
            break

        first_id = batch[0]["a"]
        last_id = batch[-1]["a"]
        last_ts = batch[-1]["T"]
        all_ids.extend(t["a"] for t in batch)
        total_trades += len(batch)

        print(f"  Page {page}: {len(batch)} trades, id {first_id}..{last_id}, {elapsed*1000:.0f}ms")

        # Advance past last timestamp
        if last_ts <= current_start:
            print(f"    STUCK: last_ts={last_ts} <= current_start={current_start}")
            break
        current_start = last_ts + 1

        if len(batch) < 1000:
            print(f"  Exhausted at page {page}")
            break

    avg_ms = sum(page_times) / len(page_times) * 1000
    print(f"\n  Total: {total_trades} trades in {n_pages} pages")
    print(f"  Avg latency: {avg_ms:.0f}ms/page")
    print(f"  Throughput: {total_trades / sum(page_times):.0f} trades/sec")

    # Check cross-page contiguity
    cross_gaps = 0
    for i in range(1, len(all_ids)):
        if all_ids[i] != all_ids[i-1] + 1:
            cross_gaps += 1
    print(f"  Cross-page ID gaps: {cross_gaps}")


def test_fromid_pagination(n_pages=5):
    """Test fromId-based pagination (potentially faster — no time filter)."""
    print(f"\n=== TEST 3: fromId pagination ({n_pages} pages) ===")

    # Get a starting point
    resp = requests.get(BASE_URL, params={"symbol": SYMBOL, "limit": "1"}, timeout=10)
    seed = resp.json()
    from_id = seed[0]["a"] - 5000  # Start 5000 trades back

    total_trades = 0
    all_ids = []
    page_times = []

    for page in range(n_pages):
        t0 = time.monotonic()
        resp = requests.get(BASE_URL, params={
            "symbol": SYMBOL,
            "fromId": str(from_id),
            "limit": "1000",
        }, timeout=10)
        elapsed = time.monotonic() - t0
        page_times.append(elapsed)

        batch = resp.json()
        if not batch:
            print(f"  Page {page}: empty")
            break

        first_id = batch[0]["a"]
        last_id = batch[-1]["a"]
        all_ids.extend(t["a"] for t in batch)
        total_trades += len(batch)

        print(f"  Page {page}: {len(batch)} trades, id {first_id}..{last_id}, {elapsed*1000:.0f}ms")

        # Advance past last ID
        from_id = last_id + 1

        if len(batch) < 1000:
            break

    avg_ms = sum(page_times) / len(page_times) * 1000
    print(f"\n  Total: {total_trades} trades in {len(page_times)} pages")
    print(f"  Avg latency: {avg_ms:.0f}ms/page")
    print(f"  Throughput: {total_trades / sum(page_times):.0f} trades/sec")

    # Check cross-page contiguity
    cross_gaps = 0
    for i in range(1, len(all_ids)):
        if all_ids[i] != all_ids[i-1] + 1:
            cross_gaps += 1
    print(f"  Cross-page ID gaps: {cross_gaps}")


def test_vision_to_rest_handoff():
    """Simulate the Vision → REST handoff using a known last Vision trade ID."""
    print("\n=== TEST 4: Vision → REST handoff simulation ===")

    # Use the last known Vision ID from our Rust validation run
    # Vision ended at id 3874910314 on 2026-02-23 23:59:59
    vision_last_id = 3874910314

    print(f"  Vision last_agg_trade_id: {vision_last_id}")
    print(f"  Requesting fromId={vision_last_id + 1} ...")

    t0 = time.monotonic()
    resp = requests.get(BASE_URL, params={
        "symbol": SYMBOL,
        "fromId": str(vision_last_id + 1),
        "limit": "1000",
    }, timeout=10)
    elapsed = time.monotonic() - t0

    batch = resp.json()
    if batch:
        first = batch[0]
        print(f"  REST first trade: id={first['a']}, T={first['T']}")
        print(f"  Expected id: {vision_last_id + 1}")
        print(f"  Match: {'YES' if first['a'] == vision_last_id + 1 else 'NO — delta=' + str(first['a'] - vision_last_id)}")
        print(f"  Latency: {elapsed*1000:.0f}ms")
    else:
        print("  Empty response (Vision ID may be too recent)")


if __name__ == "__main__":
    test_single_request()
    test_starttime_pagination()
    test_fromid_pagination()
    test_vision_to_rest_handoff()
