#!/usr/bin/env python3
"""
tracked_aircraft.py - List aircraft currently tracked by a GRX receiver.

This example retrieves the list of all tracked aircraft (state vectors)
from the Receiver API, including their position, altitude, callsign,
and signal strength.

Usage:
    python tracked_aircraft.py [HOST]

Arguments:
    HOST    IP address or hostname of the GRX (default: YOUR_GRX_IP)

Prerequisites:
    pip install grpcio grpcio-tools
    Run gen_pb.sh to generate the Python bindings.
"""

import datetime
import sys

import grpc
from google.protobuf.empty_pb2 import Empty

# Import the generated gRPC stubs for the Receiver API
import Receiverd_pb2_grpc

# ---------------------------------------------------------------------------
# Configuration
# ---------------------------------------------------------------------------

host = sys.argv[1] if len(sys.argv) >= 2 else "YOUR_GRX_IP"
RECEIVERD_PORT = 5303

# ---------------------------------------------------------------------------
# Connect and retrieve state vectors
# ---------------------------------------------------------------------------

print(f"Connecting to {host}:{RECEIVERD_PORT}...")
channel = grpc.insecure_channel(f"{host}:{RECEIVERD_PORT}")
receiverd = Receiverd_pb2_grpc.ReceiverdStub(channel)

airspace = receiverd.GetStateVectors(Empty())

# The current_timestamp field is in seconds since epoch (UTC)
timestamp = datetime.datetime.fromtimestamp(airspace.current_timestamp)
total = len(airspace.state_vectors)

print(f"\nTracked {total} aircraft at {timestamp}\n")

# ---------------------------------------------------------------------------
# Print aircraft information
# ---------------------------------------------------------------------------

# Print a CSV-like header
print(f"{'ICAO':>8s}  {'Callsign':>8s}  {'Lat':>10s}  {'Lon':>11s}  "
      f"{'Alt (ft)':>8s}  {'Ground':>6s}  {'RSS (dBm)':>9s}")
print("-" * 75)

for ac in airspace.state_vectors:
    # Format the ICAO 24-bit address as hex
    icao = f"{ac.qualified_address.address:06x}"

    # Callsign (may be empty if not yet received)
    callsign = ac.identification.strip() if ac.identification else ""

    # Position (0.0 if not available - check position_last_update)
    lat = f"{ac.position.latitude:.4f}" if ac.position_last_update else ""
    lon = f"{ac.position.longitude:.4f}" if ac.position_last_update else ""

    # Barometric altitude in feet (0 if not available)
    alt = f"{ac.barometric_altitude:.0f}" if ac.barometric_altitude_last_update else ""

    # On-ground flag
    ground = "yes" if ac.ground_flag else "no"

    # Average signal level of directly received transmissions
    rss = f"{ac.average_signal_level_directly_received:.1f}"

    print(f"{icao:>8s}  {callsign:>8s}  {lat:>10s}  {lon:>11s}  "
          f"{alt:>8s}  {ground:>6s}  {rss:>9s}")

# ---------------------------------------------------------------------------
# Clean up
# ---------------------------------------------------------------------------

channel.close()
