#!/usr/bin/env python3
"""Apply verified Analit conversion semantics and a 30-day reading path."""
import argparse
import html
import json
from pathlib import Path
import re

def ft(micros):
    return f'{micros / 1_000_000:,.2f} HUF'

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--report', type=Path, required=True)
    parser.add_argument('--periods', type=Path, required=True)
    parser.add_argument('--output', type=Path, required=True)
    args = parser.parse_args()
    periods = json.loads(args.periods.read_text())
    source = args.report.read_text()
    pattern = r'(<script type="application/json" id="dashboard-data">)(.*?)(</script>)'
    match = re.search(pattern, source, re.S)
    if not match:
        raise SystemExit('Missing embedded KPC data')
    data = json.loads(match.group(2))
    assert data['snapshotId'] == periods['snapshot']['snapshot_id']
    assert data['account']['customerId'] == periods['identity']['customer_id'] == '1938291268'
    assert data['accountTotals'] == {k: sum(v['account'][k] for v in periods['periods'].values())
        for k in ['clicks', 'impressions', 'spend_micros']}
    presence = {r['criterion_id']: r for r in periods['quality_score_presence']}
    assert presence.keys() == {k['id'] for k in data['keywords']}
    assert all(presence[k['id']]['retrieved_value'] == k['qualityScore'] for k in data['keywords'])
    evidence = dict(snapshot_id=data['snapshotId'], customer_id='1938291268',
        conversion_semantics=dict(state='retrieved', source='customer segmented by conversion_action_name',
            period_actions={n: p['conversion_actions'] for n,p in periods['periods'].items()},
            limitation='Platform form events, CRM receipt and business outcomes unverified'),
        quality_scores=[dict(criterion_id=cid, source='ad_group_criterion.quality_info.quality_score',
            value=r['retrieved_value'] if r['field_present'] else None,
            state='retrieved' if r['field_present'] else 'unavailable',
            reason=None if r['field_present'] else 'Optional provider field absent; raw protobuf scalar default is zero')
            for cid,r in presence.items()],
        planner_scope=dict(state='unavailable', reason='No language or geographic target configured'))
    # Keep canonical JSON and schema field names byte-identical. Only the
    # presentation around it changes. The family schema calls all conversion
    # action totals phone_click_conversions, which is wrong for this client.
    before, after = source[:match.start()], source[match.end():]
    def correct(text):
        text = text.replace('Phone-click events', 'Google Ads conversion events')
        text = text.replace('phone-click events', 'Google Ads conversion events')
        text = text.replace('phone-click event', 'Google Ads conversion event')
        text = text.replace('phone-click conversions', 'Google Ads conversion events')
        text = text.replace('Human approval required', 'Read-only review')
        text = text.replace(':fmt(row.qualityScore);', ':((row.qualityScore===null||row.qualityScore===0)?\'<span class="badge na">Unavailable</span><div class="subtle">Google Ads returned no current Quality Score</div>\':fmt(row.qualityScore));')
        text = re.sub(r'Observed period fields use \d{4}-\d{2}-\d{2} to \d{4}-\d{2}-\d{2}',
            f"Observed period fields use {data['window']['start']} to {data['window']['end']}", text)
        return text
    before, after = correct(before), correct(after)
    latest = periods['periods']['latest_30d']
    prior = periods['periods']['prior_30d']
    esc = html.escape
    campaign_rows = ''.join('<tr><td>' + esc(c['name']) + '</td><td>' + ft(c['spend_micros'])
        + '</td><td>' + str(c['clicks']) + '</td><td>' + str(c['conversions']) + '</td></tr>'
        for c in sorted(latest['campaigns'], key=lambda x:x['spend_micros'], reverse=True)
        if c['spend_micros'] or c['clicks'])
    keyword_rows = ''.join('<tr><td>' + esc(k['keyword_text']) + '</td><td>' + esc(k['match_type'])
        + '</td><td>' + esc(k['campaign_name']) + '</td><td>' + ft(k['spend_micros'])
        + '</td><td>' + str(k['clicks']) + '</td><td>' + str(k['impressions']) + '</td></tr>'
        for k in latest['keywords'][:10])
    comparison = '<section id="analit-period-comparison" class="registry" style="margin-top:20px">' \
        + '<h2>Latest 30 days: protect the evidence before changing spend</h2>' \
        + '<p>Provider account: ' + esc(periods['identity']['name']) + ' · 193-829-1268. Fresh snapshot ' \
        + esc(data['snapshotId']) + '. Recommendations are investigations. No Ads settings were changed.</p>' \
        + '<p><a href="decision-brief.md">Prioritized decision brief</a> · ' \
        + '<a href="workflow/SKILL.md">Reusable Analit workflow</a> · ' \
        + '<a href="workflow/period_metrics.py">Period helper</a> · ' \
        + '<a href="workflow/presentation.py">Presentation helper</a> · ' \
        + '<a href="workflow/validate_advice.py">Advice validator</a></p>' \
        + '<div class="registry-wrap"><table class="registry-table"><thead><tr><th>Period</th><th>Spend</th><th>Clicks</th><th>Impressions</th><th>Ads conversion events</th></tr></thead><tbody>'
    for label, p in [('Latest 30 days', latest), ('Prior 30 days', prior)]:
        m = p['account']
        comparison += '<tr><td>' + label + '<span class="registry-sub">' + p['start'] + ' to ' + p['end'] \
            + '</span></td><td>' + ft(m['spend_micros']) + '</td><td>' + str(m['clicks']) \
            + '</td><td>' + str(m['impressions']) + '</td><td>' + str(m['conversions']) + '</td></tr>'
    comparison += '</tbody></table></div><p><strong>Conversion definition changed.</strong> Latest events: ' \
        + esc(', '.join(a['name'] + ' (' + str(a['conversions']) + ')' for a in latest['conversion_actions'])) \
        + '. Prior events: ' + esc(', '.join(a['name'] + ' (' + str(a['conversions']) + ')' for a in prior['conversion_actions'])) \
        + '. These are platform form events. CRM receipt, qualified enquiries, bookings, revenue and contribution margin are unverified. ' \
        + 'The conversion trend and cost per event cannot establish improved ROI.</p>' \
        + '<p>The inherited KPC data field phone_click_conversions aggregates all conversion actions. Its values here are not a verified call count. ' \
        + 'Tracking coverage remains unknown. Current zero conversions do not justify stopping a keyword.</p>' \
        + '<p>Quality Score zero in the inherited raw data means the optional provider field is absent, not a score of zero. ' \
        + str(sum(not r['field_present'] for r in periods.get('quality_score_presence', []))) \
        + ' keyword rows have no current score. Planner estimates are not scoped to a configured language or geography.</p>' \
        + '<h3>Where the latest spend went</h3><div class="registry-wrap"><table class="registry-table"><thead><tr><th>Campaign</th><th>Spend</th><th>Clicks</th><th>Ads events</th></tr></thead><tbody>' \
        + campaign_rows + '</tbody></table></div><details><summary>Ten highest-spend current keywords in the latest 30 days</summary>' \
        + '<div class="registry-wrap"><table class="registry-table"><thead><tr><th>Keyword</th><th>Match</th><th>Campaign</th><th>Spend</th><th>Clicks</th><th>Impressions</th></tr></thead><tbody>' \
        + keyword_rows + '</tbody></table></div></details></section>'
    before = before.replace('</header>', '</header>' + comparison, 1)
    output = before + match.group(0) + after
    output = output.replace('</main>', '</main><script type="application/json" id="analit-presentation-evidence">'
        + json.dumps(evidence, separators=(',', ':'), ensure_ascii=False).replace('</', '<\\/') + '</script>', 1)
    args.output.parent.mkdir(parents=True, exist_ok=True)
    args.output.write_text(output)
    args.output.with_suffix('.evidence.json').write_text(json.dumps(evidence, indent=2, ensure_ascii=False))
    print(json.dumps(dict(output=str(args.output), snapshot_id=data['snapshotId'],
                         embedded_data_unchanged=True, account_periods_reconciled=True)))

if __name__ == '__main__':
    main()
