#!/usr/bin/env python3
"""
Laptop ZMQ JPEG viewer (OpenCV window)
- Subscribes to robot ZMQ PUB stream (single-part JPEG)
- Displays live video in a popup window
- Optional FPS + frame age overlay

Run:
  pip install pyzmq opencv-python numpy
  python laptop_zmq_viewer.py --robot 192.168.123.164 --port 55555

Keys:
  q  -> quit
  f  -> toggle overlay
"""

import time
import argparse
import zmq
import cv2
import numpy as np


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--robot", default="10.255.254.86", help="Robot IP that publishes ZMQ JPEG")
    ap.add_argument("--port", type=int, default=55555, help="ZMQ port (from cam_config_client.yaml)")
    ap.add_argument("--hwm", type=int, default=1, help="ZMQ high-water-mark (keep latest frames)")
    ap.add_argument("--timeout_ms", type=int, default=1000, help="ZMQ poll timeout")
    ap.add_argument("--window", default="G1 Head Camera", help="OpenCV window name")
    args = ap.parse_args()

    robot_ip = args.robot
    port = args.port

    # -----------------------
    # ZMQ subscriber
    # -----------------------
    ctx = zmq.Context.instance()
    sub = ctx.socket(zmq.SUB)
    sub.setsockopt(zmq.RCVHWM, args.hwm)
    sub.setsockopt(zmq.LINGER, 0)
    sub.setsockopt_string(zmq.SUBSCRIBE, "")
    sub.connect(f"tcp://{robot_ip}:{port}")

    poller = zmq.Poller()
    poller.register(sub, zmq.POLLIN)

    print(f"[INFO] Subscribing to tcp://{robot_ip}:{port}")
    print("[INFO] Press 'q' to quit, 'f' to toggle overlay")

    # -----------------------
    # Stats
    # -----------------------
    show_overlay = True
    last_frame_ts = 0.0
    fps = 0.0
    fps_count = 0
    t0 = time.monotonic()

    cv2.namedWindow(args.window, cv2.WINDOW_NORMAL)

    while True:
        events = dict(poller.poll(timeout=args.timeout_ms))
        if sub not in events:
            # no frame received
            # show a black frame with warning (optional)
            black = np.zeros((480, 640, 3), dtype=np.uint8)
            cv2.putText(black, "No frames...", (20, 50),
                        cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 0, 255), 2, cv2.LINE_AA)
            cv2.imshow(args.window, black)
        else:
            jpg = sub.recv()  # single-part JPEG bytes
            arr = np.frombuffer(jpg, dtype=np.uint8)
            img = cv2.imdecode(arr, cv2.IMREAD_COLOR)

            if img is None:
                continue

            now = time.monotonic()
            last_frame_ts = now

            # FPS estimate (every 10 frames)
            fps_count += 1
            if fps_count >= 10:
                dt = now - t0
                if dt > 0:
                    fps = fps_count / dt
                t0 = now
                fps_count = 0

            if show_overlay:
                age_ms = (time.monotonic() - last_frame_ts) * 1000.0
                text = f"FPS: {fps:.1f} | Age: {age_ms:.0f} ms"
                cv2.putText(img, text, (12, 28),
                            cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2, cv2.LINE_AA)

            cv2.imshow(args.window, img)

        key = cv2.waitKey(1) & 0xFF
        if key == ord("q"):
            break
        if key == ord("f"):
            show_overlay = not show_overlay

    cv2.destroyAllWindows()
    sub.close()
    ctx.term()


if __name__ == "__main__":
    main()
