import asyncio, json, websockets

async def test_4d():
    ws = await websockets.connect("ws://127.0.0.1:6007")
    
    # 0. undo_history (editor-side, no game needed)
    await ws.send(json.dumps({"id": "u1", "method": "undo_history", "params": {}}))
    r = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
    print("UNDO:", json.dumps(r.get("result", {}), indent=2)[:300])

    # 1. Start game
    await ws.send(json.dumps({"id": "r1", "method": "run", "params": {}}))
    r = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
    print("RUN:", r["status"])
    await asyncio.sleep(4)

    # 2. nav_query
    await ws.send(json.dumps({"id": "n1", "method": "nav_query", "params": {
        "from_position": [0, 0, 0], "to_position": [3, 0, -3]
    }}))
    while True:
        raw = await asyncio.wait_for(ws.recv(), timeout=10)
        data = json.loads(raw)
        if "event" in data: continue
        if data.get("id") == "n1":
            res = data.get("result", {})
            err = res.get("error", "")
            if err: print("NAV: ERROR", err)
            else: print("NAV: reachable=%s dist=%.1f eff=%.2f pts=%d" % (
                res.get("reachable"), res.get("distance",0), res.get("efficiency_ratio",0), res.get("waypoint_count",0)))
            break

    # 3. watch start
    await ws.send(json.dumps({"id": "w1", "method": "watch", "params": {
        "action": "start", "watches": [{"node": "GameManager", "properties": ["current_day"]}], "sample_interval_ms": 200
    }}))
    while True:
        raw = await asyncio.wait_for(ws.recv(), timeout=5)
        data = json.loads(raw)
        if "event" in data: continue
        if data.get("id") == "w1": print("WATCH START:", json.dumps(data.get("result", {}))); break

    await asyncio.sleep(2)

    # 4. watch read
    await ws.send(json.dumps({"id": "w2", "method": "watch", "params": {"action": "read"}}))
    while True:
        raw = await asyncio.wait_for(ws.recv(), timeout=5)
        data = json.loads(raw)
        if "event" in data: continue
        if data.get("id") == "w2":
            res = data.get("result", {})
            print("WATCH READ: %d events, %d active" % (res.get("events_total",0), res.get("watches_active",0)))
            break

    # 5. watch stop
    await ws.send(json.dumps({"id": "w3", "method": "watch", "params": {"action": "stop"}}))
    while True:
        raw = await asyncio.wait_for(ws.recv(), timeout=5)
        data = json.loads(raw)
        if "event" in data: continue
        if data.get("id") == "w3": print("WATCH STOP:", json.dumps(data.get("result", {}))); break

    # 6. Stop game
    await ws.send(json.dumps({"id": "s1", "method": "stop", "params": {}}))
    r = json.loads(await asyncio.wait_for(ws.recv(), timeout=5))
    print("STOP:", r["status"])

    await ws.close()
    print("\nAll 4d tools tested!")

asyncio.run(test_4d())
