import os, sys, time, random, aprslib

# ---- config via env ----
CALLSIGN = os.environ.get("APRS_CALLSIGN","W1HD")
PASSCODE = os.environ.get("APRS_PASSCODE","27799")
HOST     = os.environ.get("APRS_HOST","noam.aprs2.net")
PORT     = int(os.environ.get("APRS_PORT","14580"))
FILTER   = os.environ.get("APRS_FILTER","b/W1HD-9")
LOGFILE  = os.environ.get("APRS_LOGFILE","/home/bbl/html/w1hd-tracker/W1HD-9_packets.log")

# App identification (two tokens after 'vers')
APPNAME  = os.environ.get("APRS_APPNAME","w1hd-tracker")
APPVER   = os.environ.get("APRS_APPVER","1.0_k1te.bradshaw@lupton.us_BuzzardsBayMA_+15088736867")

# Polite reconnects
BACKOFF_START = int(os.environ.get("APRS_BACKOFF_START","10"))
BACKOFF_MAX   = int(os.environ.get("APRS_BACKOFF_MAX","600"))
JITTER_MAX    = float(os.environ.get("APRS_JITTER_MAX","3.0"))

def log_line(s: str):
    ts = time.strftime("%Y-%m-%dT%H:%M:%S%z")
    try:
        with open(LOGFILE, "a", buffering=1) as f:
            f.write(f"{ts} {s}\n")
    except Exception as e:
        sys.stderr.write(f"write-error: {e}\n")

def packet_handler(pkt):
    # raw=True hands us the raw APRS-IS line
    line = pkt if isinstance(pkt, str) else str(pkt)
    log_line(line)

backoff = BACKOFF_START

while True:
    try:
        # 1) build IS without appid kwarg (for compatibility)
        ais = aprslib.IS(CALLSIGN, passwd=PASSCODE, host=HOST, port=PORT)

        # 2) set the app id string *after* construction
        #    Must be TWO space-separated tokens after 'vers'
        ais.appid = f"{APPNAME} {APPVER}"

        # 3) filter + connect + start consuming
        ais.set_filter(FILTER)
        ais.connect()
        log_line(f"# START {CALLSIGN}@{HOST}:{PORT} appid=[{ais.appid}] filter=[{FILTER}]")

        # reset backoff after a successful connect
        backoff = BACKOFF_START

        # stream packets
        ais.consumer(packet_handler, raw=True)

    except Exception as e:
        log_line(f"# DISCONNECT: {e}")
        # polite backoff with a little jitter
        jitter = random.uniform(0.0, JITTER_MAX)
        wait = min(backoff, BACKOFF_MAX) + jitter
        log_line(f"# BACKOFF: sleeping {wait:.1f}s (polite mode); will retry")
        time.sleep(wait)
        backoff = min(int(backoff * 2), BACKOFF_MAX)
