"""Rules E: Google Ads integration (G15, G16)."""
from collections import defaultdict
from .common import GA4_PREFIX, LEAD_CATEGORIES, NATIVE_TYPES, ads_id, digits, get, kv, n0, num, pct, up

def g15(c, f):
    if c.ads_links is None: return f.nc('Google Ads links not read')
    g = c.cfg.get('google_ads') or {}
    exp, ret, third = ({digits(x) for x in g.get(k) or []} for k in ('expected_customer_ids', 'retired_customer_ids', 'third_party_customer_ids'))
    uses = c.cfg.get('ga4_key_events_imported_to_ads') or c.cfg.get('ga4_audiences_used_in_ads')
    if not c.ads_links and not exp and not uses: return f.na('no Google Ads link and none expected')
    linked = {digits(get(x, 'customerId')): x for x in c.ads_links}
    for e in sorted(exp - set(linked)):
        if uses: f.fail(f'expected Google Ads account {ads_id(e)} has no link, so imports and audiences stop')
        else: f.warn(f'expected Google Ads account {ads_id(e)} has no link')
    for cid, x in linked.items():
        pers = ', ads personalization on' if get(x, 'adsPersonalizationEnabled') else ''
        if cid in third: f.fail(f'linked to {ads_id(cid)}, which the config marks as owned by a third party{pers}')
        elif cid in ret: f.warn(f'link to retired account {ads_id(cid)}{pers}')
        elif exp and cid not in exp: f.warn(f'link to unknown account {ads_id(cid)}{pers}')
        if get(x, 'canManageClients'):
            f.warn(f'{ads_id(cid)} is a manager account link: imports become available to every client account under it')
    cpc = c.agg('R10', 'sessionGoogleAdsCustomerId', 'sessions')
    tot = sum(cpc.values())
    none = sum(v for k, v in cpc.items() if k in ('', '(not set)'))
    if tot and none / tot >= c.th['ads_no_customer_share']:
        f.warn(f'{pct(none / tot)} of {n0(tot)} google / cpc sessions have no Google Ads customer ID (auto-tagging off, an unlinked account or manual UTMs)')
    f.ok('expected links only; Google Ads dimensions populated')

def counting_kind(v):
    """'once' or 'every' from GA4 or Google Ads counting wording; '' when unknown."""
    s = str(v or '').strip().lower().replace('_', ' ')
    if 'session' in s or s in ('one', 'one per click'): return 'once'
    if 'event' in s or 'every' in s or 'many' in s: return 'every'
    return ''

def g16(c, f):
    att, imported = get(c.snap, 'attributionSettings'), c.cfg.get('ga4_key_events_imported_to_ads')
    conv = [(k, v) for k, v in c.uirows('conversions.') if v.lower() != 'none']
    if c.ads_links == [] and not imported and not c.ads and not conv: return f.na('no Google Ads link and nothing imported')
    if att is None and c.ads is None and not conv:
        return f.nc('attribution settings, GA4 conversions and Google Ads conversion actions not read')
    if att is not None and 'NOT_SELECTED' in up(get(att, 'adsWebConversionDataExportScope')) and imported:
        f.warn('conversion export scope is NOT_SELECTED_YET while GA4 key events are imported to Google Ads')
    cycle = int(c.cfg.get('sales_cycle_days') or 0)
    for key, v in conv:
        d, name = kv(v), key.split('.', 1)[1]
        ke = d.get('key_event') or name
        want, have = up((c.intended.get(ke) or {}).get('counting')), counting_kind(d.get('counting'))
        if want and have and have != ('once' if 'SESSION' in want else 'every'):
            f.warn(f'GA4 conversion "{name}" counts {d.get("counting")} while the tracking plan counts {ke} {want}' + c.ev(key))
        win = num(d.get('click_window_days'))
        if cycle and win and win < cycle and c.ads is None:  # with Google Ads results the same window is rated below
            f.warn(f'GA4 conversion "{name}" has a {win:g}-day click-through window, shorter than the {cycle}-day sales cycle' + c.ev(key))
    if c.ads is None: f.partial.append('no Google Ads read access: imported and native actions not compared')
    else:
        acts = [a for a in c.ads.get('conversion_actions') or [] if up(a.get('status')) == 'ENABLED']
        cats = defaultdict(lambda: ([], []))
        for a in acts:
            t = up(a.get('type'))
            if a.get('primary_for_goal') and (t.startswith(GA4_PREFIX) or t in NATIVE_TYPES):
                cats[up(a.get('category'))][t in NATIVE_TYPES].append(a.get('name'))
        groups = [set(g) for g in c.cfg.get('ads_same_outcome_actions') or []]
        for cat, (ga4, native) in cats.items():
            if not ga4 or not native: continue
            text = f'{cat}: GA4-imported "{", ".join(ga4)}" and native or uploaded "{", ".join(native)}" are both primary'
            if cat == 'PURCHASE' or any(g & set(ga4) and g & set(native) for g in groups):
                f.fail(text + ', so one outcome counts twice for bidding')
            else: f.warn(text + '; confirm they measure different outcomes, otherwise one outcome counts twice')
        ua = [a.get('name') for a in acts if up(a.get('type')).startswith('UNIVERSAL_ANALYTICS')]
        if ua: f.warn(f'Universal Analytics conversion actions still ENABLED: {", ".join(ua)}')
        sec = {a.get('name') for a in acts if not a.get('primary_for_goal')}
        for n in c.ads.get('custom_goal_actions') or []:
            if n in sec: f.warn(f'secondary action "{n}" is in a custom goal, so it is still biddable')
        many = [a.get('name') for a in acts if up(a.get('category')) in LEAD_CATEGORIES and up(a.get('counting_type')) == 'MANY_PER_CLICK']
        if many:
            f.warn(f'lead actions count every conversion per click (MANY_PER_CLICK): {", ".join(many)}; '
                   'Google suggests One for leads (answer 3438531), so repeat submissions inflate lead counts')
        short = [f'{a.get("name")} ({int(num(a.get("click_through_lookback_window_days")))} days)' for a in acts
                 if a.get('primary_for_goal') and cycle and 0 < num(a.get('click_through_lookback_window_days')) < cycle]
        if short: f.warn(f'primary actions with a click-through window shorter than the {cycle}-day sales cycle: {", ".join(short)}')
    f.ok('; '.join(x for x, ok in (('one primary action per outcome in Google Ads', c.ads is not None),
                                    ('export scope chosen', att is not None),
                                    ('GA4 conversion settings match the tracking plan', bool(conv))) if ok))
