"""Feed recorded RTCM data into an NTRIP caster as a SOURCE connection.

Acts as a fake base station, pushing recorded RTCM binary data to a
caster's mount point. The caster then distributes it to connected
rover clients.

Usage:
    python feeder.py --host localhost --mount kunaidaho \
        --password rtcm2024 --rtcm-file data/kunaidaho.bin

The feeder loops the recorded data continuously at a configurable
rate, simulating a live base station stream.
"""

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


def feed(
    host: str,
    port: int,
    mount: str,
    password: str,
    rtcm_file: Path,
    rate: float,
    loop: bool,
) -> None:
    """Push RTCM data to a caster as an NTRIP SOURCE."""
    data = rtcm_file.read_bytes()
    print(f"Loaded {len(data):,} bytes from {rtcm_file}", file=sys.stderr)

    while True:
        sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        sock.settimeout(10)

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

            # NTRIP 1.0 SOURCE protocol
            request = f"SOURCE {password} /{mount}\r\n\r\n"
            sock.send(request.encode())

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

            if "OK" not in resp_str.upper() and "ICY" not in resp_str.upper():
                print(f"ERROR: SOURCE rejected: {resp_str}", file=sys.stderr)
                sock.close()
                if loop:
                    time.sleep(5)
                    continue
                return

            # Stream RTCM data at specified rate
            chunk_size = 256
            offset = 0
            total = 0
            start = time.time()

            print(f"Streaming at {rate:.0f} B/s (Ctrl+C to stop)...", file=sys.stderr)
            while True:
                end = offset + chunk_size
                if end > len(data):
                    if not loop:
                        break
                    # Wrap around
                    chunk = data[offset:] + data[:end - len(data)]
                    offset = end - len(data)
                else:
                    chunk = data[offset:end]
                    offset = end

                sock.send(chunk)
                total += len(chunk)

                elapsed = time.time() - start
                if total % 5000 < chunk_size:
                    print(
                        f"\r  Sent {total:,} bytes ({elapsed:.0f}s, "
                        f"{total/max(elapsed,0.1):.0f} B/s)",
                        end="", file=sys.stderr,
                    )

                if rate > 0:
                    time.sleep(chunk_size / rate)

        except (ConnectionResetError, BrokenPipeError, ConnectionRefusedError) as e:
            print(f"\nConnection lost: {e}", file=sys.stderr)
        except KeyboardInterrupt:
            print(f"\nStopped after {total:,} bytes", file=sys.stderr)
            sock.close()
            return
        finally:
            sock.close()

        if not loop:
            break
        print("\nReconnecting in 5s...", file=sys.stderr)
        time.sleep(5)


def main():
    parser = argparse.ArgumentParser(
        description="Feed recorded RTCM data into an NTRIP caster as SOURCE",
    )
    parser.add_argument("--host", default="localhost", help="Caster host")
    parser.add_argument("--port", type=int, default=2101, help="Caster port")
    parser.add_argument("--mount", required=True, help="Mount point name")
    parser.add_argument("--password", required=True, help="SOURCE/encoder password")
    parser.add_argument("--rtcm-file", type=Path, required=True, help="RTCM binary file")
    parser.add_argument("--rate", type=float, default=600.0, help="Stream rate B/s (0=unlimited)")
    parser.add_argument("--no-loop", action="store_true", help="Don't loop (send file once)")
    args = parser.parse_args()

    if not args.rtcm_file.exists():
        print(f"ERROR: {args.rtcm_file} not found", file=sys.stderr)
        sys.exit(1)

    feed(
        host=args.host,
        port=args.port,
        mount=args.mount,
        password=args.password,
        rtcm_file=args.rtcm_file,
        rate=args.rate,
        loop=not args.no_loop,
    )


if __name__ == "__main__":
    main()
