#!/usr/bin/env python3
"""Scores scripts/run-ads-prospect-check.py output: per prospect and route, ads returned, most recent shown date, whether the
advertiser name matches the business, and whether the prospect counts as running ads (Google: an ad last shown within 30 days of
the run; Meta: at least one active US ad). No provider call. Writes summary.json beside raw/.
Usage: scripts/score-ads-prospect-check.py evidence/fixtures/ads-prospects-v1.json evidence/ads-prospect-checks/YYYY-MM-DD"""
import json, sys, os, re, csv, datetime as dt
fx = json.load(open(sys.argv[1])); base = sys.argv[2]; raw = os.path.join(base, 'raw')
PRICE = {'google/sc': 0.00188, 'google/adyntel': 0.011, 'google/serpapi': 0.015, 'meta/adyntel': 0.011, 'meta/sc': 0.00188}
def day(v):
    if v is None: return None
    if isinstance(v, (int, float)): return dt.datetime.utcfromtimestamp(v).date()
    return dt.date.fromisoformat(str(v)[:10])
def parse(route, r):
    """-> (ok, n_ads_returned, estimate, last_shown, advertiser_names, page_names)"""
    if r == {'_nonjson': ''}: return (True, 0, None, None, set(), set())  # Adyntel answers 204 No Content (not billed) when it finds no Facebook page for the domain
    if r.get('detail') or r.get('success') is False or '_nonjson' in r: return (False, 0, None, None, set(), set())
    if route == 'google/sc':
        ads = r.get('ads') or []
        return (True, len(ads), r.get('number_of_ads_estimate'), max([day(a.get('lastShown')) for a in ads if a.get('lastShown')], default=None), {a.get('advertiserName') for a in ads if a.get('advertiserName')}, set())
    if route == 'google/adyntel':
        ads = r.get('ads') or []
        return (True, len(ads), r.get('total_ad_count') or r.get('number_of_ads'), max([day(a.get('last_seen')) for a in ads if a.get('last_seen')], default=None), {a.get('advertiser_name') for a in ads if a.get('advertiser_name')}, set())
    if route == 'google/serpapi':
        ads = r.get('ad_creatives') or []
        return (True, len(ads), (r.get('search_information') or {}).get('total_results'), max([day(a.get('last_shown')) for a in ads if a.get('last_shown')], default=None), {a.get('advertiser') for a in ads if a.get('advertiser')}, set())
    if route == 'meta/adyntel':
        ads = r.get('results') or []
        return (True, len(ads), r.get('number_of_ads'), None, set(), {(a.get('snapshot') or {}).get('page_name') for a in ads if (a.get('snapshot') or {}).get('page_name')})
    if route == 'meta/sc':
        ads = r.get('results') or []
        return (True, len(ads), r.get('searchResultsCount'), None, set(), {a.get('page_name') or (a.get('snapshot') or {}).get('page_name') for a in ads} - {None})
STOP = {'inc', 'llc', 'the', 'and', 'company', 'services', 'group', 'law', 'llp', 'corporation', 'professional'}
def toks(x): return {t for t in re.findall(r'[a-z0-9]+', x.lower()) if t not in STOP and len(t) > 2}
rows = []; run_day = None
for p in fx['prospects']:
    row = {k: p[k] for k in ('id', 'category', 'name', 'domain')}
    for route in PRICE:
        plat, prov = route.split('/')
        rec = json.load(open(os.path.join(raw, f'{plat}-{prov}-{p["id"]}.json')))
        run_day = run_day or day(rec['_run']['ts'])
        ok, n, est, last, adv, pages = parse(route, rec['response'])
        running = (n > 0) if plat == 'meta' else (last is not None and (run_day - last).days <= 30)
        row[route] = {'ok': ok, 'ads_returned': n, 'estimate': est, 'last_shown': str(last) if last else None, 'running': running,
                      'advertisers': sorted(adv), 'pages': sorted(pages), 'latency_ms': rec['_run']['latency_ms']}
    advs = set(row['google/sc']['advertisers']) | set(row['google/adyntel']['advertisers']) | set(row['google/serpapi']['advertisers'])
    # Payer names stay out of the published copy (some are individuals); keep only whether any of them matches the business name.
    row['google_advertiser_matches_name'] = (any(toks(a) & toks(p['name']) for a in advs)) if advs else None
    for route in PRICE: row[route].pop('advertisers')
    rows.append(row)
def share(route): return sum(r[route]['running'] for r in rows)
summary = {'run_utc_date': str(run_day), 'fixture': fx['name'], 'prospects': len(rows), 'prices_usd_per_call': PRICE,
           'running_by_route': {k: share(k) for k in PRICE},
           'errors_by_route': {k: sum(not r[k]['ok'] for r in rows) for k in PRICE},
           'google_any': sum(any(r[k]['running'] for k in PRICE if k.startswith('google')) for r in rows),
           'meta_any': sum(any(r[k]['running'] for k in PRICE if k.startswith('meta')) for r in rows),
           'either': sum(any(r[k]['running'] for k in PRICE) for r in rows),
           'google_routes_disagree': [r['id'] for r in rows if len({r[k]['running'] for k in PRICE if k.startswith('google')}) > 1],
           'meta_routes_disagree': [r['id'] for r in rows if len({r[k]['running'] for k in PRICE if k.startswith('meta')}) > 1],
           'rows': rows}
summary['google_advertiser_name_differs'] = [r['id'] for r in rows if r['google_advertiser_matches_name'] is False]
json.dump(summary, open(os.path.join(base, 'summary.json'), 'w'), indent=1)
with open(os.path.join(base, 'prospects.csv'), 'w', newline='') as f:
    w = csv.writer(f); w.writerow(['id', 'category', 'name', 'domain', 'google_advertiser_matches_name'] + [f'{k}_{c}' for k in PRICE for c in ('running', 'ads_returned', 'estimate', 'last_shown')])
    for r in rows: w.writerow([r['id'], r['category'], r['name'], r['domain'], r['google_advertiser_matches_name']] + [r[k][c] for k in PRICE for c in ('running', 'ads_returned', 'estimate', 'last_shown')])
print(json.dumps({k: v for k, v in summary.items() if k != 'rows'}, indent=1))
