#!/usr/bin/env python3

import asyncio
import json
import redis
import websockets
from datetime import datetime, timezone

REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 0
REDIS_PASSWORD = None
REDIS_HASH_KEY = "us_market:last_prices"

WS_HOST = "127.0.0.1"
WS_PORT = 8765

SNAPSHOT_INTERVAL = 5  # seconds

r = redis.Redis(
    host=REDIS_HOST,
    port=REDIS_PORT,
    db=REDIS_DB,
    password=REDIS_PASSWORD,
    decode_responses=True,
)


def build_full_snapshot():
    """
    Return the full Redis snapshot as one payload containing all symbols.
    Example:
    {
        "timestamp": "2026-03-25T18:30:00Z",
        "data": [
            {"symbol": "AAPL", "price": "213.45"},
            {"symbol": "MSFT", "price": "387.12"}
        ]
    }
    """
    snapshot = r.hgetall(REDIS_HASH_KEY)

    items = [
        {"symbol": sym, "price": price}
        for sym, price in snapshot.items()
    ]

    # Optional: sort symbols for stable output
    items.sort(key=lambda x: x["symbol"])

    return {
        "timestamp": datetime.now(timezone.utc).isoformat().replace("+00:00", "Z"),
        "data": items
    }


async def send_snapshot_every_minute(websocket):
    """
    Send one full snapshot immediately, then every 60 seconds.
    """
    try:
        while True:
            payload = await asyncio.to_thread(build_full_snapshot)
            await websocket.send(json.dumps(payload, separators=(",", ":")))
            await asyncio.sleep(SNAPSHOT_INTERVAL)

    except Exception as exc:
        print("Snapshot stream error:", exc)


async def handler(websocket):

    try:
        # Ignore any incoming client message.
        # This server always sends all symbols once every minute.
        await send_snapshot_every_minute(websocket)

    except Exception as exc:
        print("Handler error:", exc)


async def main():
    print(f"WebSocket server running on ws://{WS_HOST}:{WS_PORT}")
    server = await websockets.serve(
        handler,
        WS_HOST,
        WS_PORT,
        ping_interval=20,
        ping_timeout=20,
        max_queue=8,
    )
    await server.wait_closed()


if __name__ == "__main__":
    asyncio.run(main())