import http.client, ssl, socket, urllib.request, time, datetime
from concurrent.futures import ThreadPoolExecutor

LOG     = "/tmp/cujo-tracker.log"
SUMMARY = "/tmp/cujo-summary.txt"
INTERVAL = 90            # seconds between passes
DURATION_MIN = 600       # total run time (long unattended monitoring for de-listing)

# storefront targets: checked on BOTH port 80 (CUJO) and 443 (TLS — the real user symptom)
TARGETS = ["www.drinktrade.com", "drinktrade.com"]
# the 25 flagged subdomains: checked on port 80 (CUJO fingerprint)
SUBS = [
    "blog.drinktrade.com","buy.drinktrade.com","cobalt-ridge-4821.drinktrade.com",
    "coffee-recommender-production.drinktrade.com","coffee-recommender-staging.drinktrade.com",
    "data.drinktrade.com","go.drinktrade.com","go.qa.drinktrade.com","help.drinktrade.com",
    "kbounces.drinktrade.com","links.drinktrade.com","partners.drinktrade.com",
    "pine-crest-7293-api.drinktrade.com","qa-account-dev.drinktrade.com",
    "qa-account-dev-vincent.drinktrade.com","roasters.drinktrade.com","share.drinktrade.com",
    "sms.drinktrade.com","ss.drinktrade.com","ss2.drinktrade.com","staging.app.drinktrade.com",
    "staging.data.drinktrade.com","staging.roasters.drinktrade.com","trade-n8n-qa.drinktrade.com",
    "trk.drinktrade.com",
]

def now(): return datetime.datetime.now().strftime("%H:%M:%S")
def wan():
    try: return urllib.request.urlopen("https://api.ipify.org", timeout=6).read().decode()
    except Exception: return "?"
def cujo80(h):
    try:
        c = http.client.HTTPConnection(h, 80, timeout=6); c.request("GET", "/", headers={"Host": h})
        r = c.getresponse(); loc = (r.getheader("Location") or ""); c.close()
        return "CUJO" if "cujo" in loc.lower() else "clear"
    except Exception: return "err"
def tls443(h):
    try:
        with ssl.create_default_context().wrap_socket(socket.create_connection((h,443),timeout=6),server_hostname=h) as s:
            return "ok"
    except Exception: return "FAIL"
def short(h): return h.replace(".drinktrade.com","") if h!="drinktrade.com" else "apex"

hist = {h: [] for h in TARGETS+SUBS}   # per-pass state string
def logline(s):
    with open(LOG,"a") as f: f.write(s+"\n")

def trend(h): return "".join("B" if x in ("CUJO","HIT") else ("." if x in ("clear","ok") else "_") for x in hist[h][-16:])

def write_summary(passn, wanip):
    L = []
    ever = [short(h) for h in TARGETS if "HIT" in hist[h]]
    L.append("="*64)
    L.append(f"CUJO COMBINED TRACKER — {now()} | pass {passn} | WAN {wanip}")
    L.append(f"interval {INTERVAL}s, {DURATION_MIN}min run | legend: B=blocked . =clear _=unreachable")
    L.append("="*64)
    L.append("")
    L.append(">>> STOREFRONT (www / apex) — the ones that matter <<<")
    if ever:
        L.append(f"    *** ALERT: {', '.join(ever)} FLAPPED into blocked at least once! ***")
    else:
        L.append("    status: clean every pass so far (no www/apex block captured yet)")
    for h in TARGETS:
        b = hist[h].count("HIT")
        L.append(f"    {short(h):8s} blocked {b}/{len(hist[h])}   last16:{trend(h)}")
    L.append("")
    # classify subs
    buckets = {"BLOCKED (persistent)":[], "FLAPPING":[], "CLEAR / resolved":[], "UNREACHABLE":[]}
    for h in SUBS:
        hh = hist[h]; b = hh.count("CUJO"); c = hh.count("clear"); e = hh.count("err")
        lab = f"{short(h):38s} blocked {b}/{len(hh)}  last16:{trend(h)}"
        if b == 0 and c == 0 and e: buckets["UNREACHABLE"].append(lab)
        elif b == 0: buckets["CLEAR / resolved"].append(lab)
        elif c == 0 and e == 0: buckets["BLOCKED (persistent)"].append(lab)
        else: buckets["FLAPPING"].append(lab)
    L.append(f">>> 25 SUBDOMAINS <<<")
    for k in ["BLOCKED (persistent)","FLAPPING","CLEAR / resolved","UNREACHABLE"]:
        L.append(f"== {k} ({len(buckets[k])}) ==")
        L += ["   "+x for x in buckets[k]] or ["   (none)"]
    with open(SUMMARY,"w") as f: f.write("\n".join(L)+"\n")

end = time.time() + DURATION_MIN*60
logline(f"\n===== COMBINED TRACKER START {now()} WAN={wan()} interval={INTERVAL}s =====")
passn = 0
while time.time() < end:
    passn += 1
    wanip = wan() if passn % 5 == 1 else "?"
    # targets: combined state = HIT if CUJO on 80 OR FAIL on 443
    with ThreadPoolExecutor(max_workers=28) as ex:
        c80 = dict(zip(TARGETS+SUBS, ex.map(cujo80, TARGETS+SUBS)))
        t443 = dict(zip(TARGETS, ex.map(tls443, TARGETS)))
    for h in TARGETS:
        state = "HIT" if (c80[h]=="CUJO" or t443[h]=="FAIL") else ("err" if c80[h]=="err" and t443[h]=="FAIL" else "clear")
        hist[h].append(state)
    for h in SUBS: hist[h].append(c80[h])
    nb = sum(1 for h in SUBS if c80[h]=="CUJO")
    thit = [short(h) for h in TARGETS if hist[h][-1]=="HIT"]
    logline(f"[{now()} #{passn} WAN={wanip}] subs_blocked={nb}/25 www/apex_hit={thit or 'none'} "
            f":: " + " ".join(f"{short(h)}={c80[h]}" for h in SUBS if c80[h]!="clear"))
    write_summary(passn, wanip if wanip!="?" else "?")
    time.sleep(INTERVAL)
logline(f"===== TRACKER DONE {now()} passes={passn} =====")
print(f"combined tracker done: {passn} passes. Summary: {SUMMARY} | Log: {LOG}")
