"""Capture RTCM data from a remote NTRIP caster for replay testing.

Connects to a real NTRIP caster, downloads correction data for a
specified duration, and saves the raw binary for the dev caster
to replay.

Usage:
    python capture.py --host rtk2go.com --mount kunaidaho \
        --user ryan@malloys.us --password none --duration 60

Output is saved as raw RTCM3 binary, suitable for the dev caster's
data/ directory.
"""

import argparse
import base64
import socket
import sys
import time
from pathlib import Path


def capture(
    host: str,
    port: int,
    mount: str,
    user: str,
    password: str,
    duration: int,
    output: Path,
) -> None:
    """Capture RTCM data from an NTRIP mount point."""
    auth = base64.b64encode(f"{user}:{password}".encode()).decode()

    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout(10)

    print(f"Connecting to {host}:{port}/{mount}...", file=sys.stderr)
    sock.connect((host, port))

    # Try NTRIP 2.0 first, fall back to 1.0
    for http_ver, ntrip_hdr in [
        ("HTTP/1.1", "Ntrip-Version: Ntrip/2.0\r\n"),
        ("HTTP/1.0", ""),
    ]:
        request = (
            f"GET /{mount} {http_ver}\r\n"
            f"Host: {host}\r\n"
            f"User-Agent: NTRIP lc29h-capture\r\n"
            f"{ntrip_hdr}"
            f"Authorization: Basic {auth}\r\n"
            f"\r\n"
        )
        sock.send(request.encode())

        # Read response line
        resp = sock.recv(256)
        resp_str = resp.decode("latin-1").strip()
        print(f"Response ({http_ver}): {resp_str}", file=sys.stderr)

        if "200" in resp_str or "ICY" in resp_str:
            break
        if "SOURCETABLE" in resp_str:
            print("ERROR: Mount rejected (got source table)", file=sys.stderr)
            sock.close()
            sys.exit(1)

        # Reconnect for fallback
        sock.close()
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)
        sock.connect((host, port))
    else:
        print(f"ERROR: Connection failed: {resp_str}", file=sys.stderr)
        sock.close()
        sys.exit(1)

    # Capture data
    output.parent.mkdir(parents=True, exist_ok=True)
    total = 0
    start = time.time()
    sock.settimeout(5)

    print(f"Capturing {duration}s of RTCM data...", file=sys.stderr)
    with open(output, "wb") as f:
        while time.time() - start < duration:
            try:
                data = sock.recv(4096)
                if not data:
                    print("Stream ended", file=sys.stderr)
                    break
                f.write(data)
                total += len(data)
                elapsed = time.time() - start
                print(
                    f"\r  {total:,} bytes ({elapsed:.0f}s, "
                    f"{total/elapsed:.0f} B/s)",
                    end="", file=sys.stderr,
                )
            except socket.timeout:
                continue

    sock.close()
    elapsed = time.time() - start
    print(f"\nSaved {total:,} bytes to {output} ({elapsed:.1f}s)", file=sys.stderr)

    # Validate: check for RTCM3 preamble
    with open(output, "rb") as f:
        first_byte = f.read(1)
        if first_byte == b"\xd3":
            print("Validated: starts with RTCM3 preamble (0xD3)", file=sys.stderr)
        else:
            print(
                f"WARNING: first byte is 0x{first_byte[0]:02x}, "
                f"expected 0xD3 (RTCM3 preamble)",
                file=sys.stderr,
            )


def main():
    parser = argparse.ArgumentParser(
        description="Capture RTCM data from a remote NTRIP caster",
    )
    parser.add_argument("--host", required=True, help="NTRIP caster hostname")
    parser.add_argument("--port", type=int, default=2101, help="Caster port")
    parser.add_argument("--mount", required=True, help="Mount point name")
    parser.add_argument("--user", default="", help="Username (email for rtk2go)")
    parser.add_argument("--password", default="none", help="Password")
    parser.add_argument("--duration", type=int, default=60, help="Capture duration (seconds)")
    parser.add_argument("--output", type=Path, required=True, help="Output file path")
    args = parser.parse_args()

    capture(
        host=args.host,
        port=args.port,
        mount=args.mount,
        user=args.user,
        password=args.password,
        duration=args.duration,
        output=args.output,
    )


if __name__ == "__main__":
    main()
