#!/usr/bin/env python3
import argparse, csv
from collections import Counter, defaultdict
from pathlib import Path

KEY_PCS = [
    '0x9001BC28','0x9001BC38','0x9001BC3B','0x9001BC3E',
    '0x9001CFB1','0x9001CFCA','0x9001D05B','0x9001D086',
    '0x9001B9D5','0x9001BA03','0x9001BA0C',
    '0x9001EF37','0x9001EF54','0x9001EF66','0x9001EE44','0x9001EE4A',
    '0x9001B71B','0x9001B75F','0x9001B764','0x90021696',
    '0x90008824','0x9001C83E','0x90009A02','0x900210C1','0x900222FA','0x90022301'
]
KEY_ADDRS = [
    '0x000005B1','0x000005CD','0x000005C9','0x000005CE',
    '0x0000071E','0x00000722','0x00000724','0x0000076D','0x0000076E',
    '0x0000077C','0x0000077D','0x000007F8','0x000007F9',
    '0x000006E1','0x000006EC','0x000006ED','0x000006F1','0x0000DA0C','0x0000D95C',
    '0x000007E8','0x0000DF30','0x0000DF70'
]

def norm(x):
    return (x or '').strip().upper()

def main():
    ap=argparse.ArgumentParser()
    ap.add_argument('trace_csv')
    ap.add_argument('--out-md', default='gdr_partition_trace_report.md')
    ap.add_argument('--out-csv', default='gdr_partition_candidate_writes.csv')
    ns=ap.parse_args()
    p=Path(ns.trace_csv)
    rows=[]
    with p.open(newline='', encoding='utf-8', errors='replace') as f:
        for r in csv.DictReader(f):
            rows.append(r)
    events=Counter(r.get('event','') for r in rows)
    pc_counts=Counter(norm(r.get('pc')) for r in rows)
    name_counts=Counter(r.get('name','') for r in rows)

    key_pc_rows=[]
    for r in rows:
        if norm(r.get('pc')) in {x.upper() for x in KEY_PCS}:
            key_pc_rows.append(r)

    key_addr_events=[]
    for r in rows:
        if norm(r.get('addr')) in {x.upper() for x in KEY_ADDRS}:
            key_addr_events.append(r)

    # Write candidate write CSV
    with Path(ns.out_csv).open('w', newline='', encoding='utf-8') as f:
        w=csv.DictWriter(f, fieldnames=['seq','cycle','event','name','pc','addr','size','value','bytes_hex','d0','d1','d2','d3','a0','a1','sp'])
        w.writeheader()
        for r in key_addr_events:
            if r.get('event') == 'watch_write':
                w.writerow({k:r.get(k,'') for k in w.fieldnames})

    def last_write(addr):
        sub=[r for r in key_addr_events if norm(r.get('addr'))==addr.upper() and r.get('event')=='watch_write']
        return sub[-1] if sub else None

    lines=[]
    lines.append(f'# GDR partition/auth trace summary: `{p.name}`')
    lines.append('')
    lines.append(f'- rows: {len(rows)}')
    lines.append(f'- events: {dict(events)}')
    lines.append('')
    lines.append('## Key PC hit counts')
    lines.append('')
    lines.append('| PC | hits |')
    lines.append('|---:|---:|')
    for pc in KEY_PCS:
        lines.append(f'| `{pc}` | {pc_counts[pc.upper()]} |')
    lines.append('')
    lines.append('## Key address last writes')
    lines.append('')
    lines.append('| addr | last write cycle | PC | value | bytes |')
    lines.append('|---:|---:|---:|---:|---|')
    for addr in KEY_ADDRS:
        r=last_write(addr)
        if r:
            lines.append(f"| `{addr}` | {r.get('cycle','')} | `{r.get('pc','')}` | `{r.get('value','')}` | `{r.get('bytes_hex','')}` |")
        else:
            lines.append(f'| `{addr}` |  |  |  |  |')
    lines.append('')
    lines.append('## Top PCs')
    lines.append('')
    lines.append('| PC | hits |')
    lines.append('|---:|---:|')
    for pc,n in pc_counts.most_common(20):
        if pc:
            lines.append(f'| `{pc}` | {n} |')
    lines.append('')
    lines.append('## Top watch names')
    lines.append('')
    lines.append('| name | hits |')
    lines.append('|---|---:|')
    for name,n in name_counts.most_common(20):
        lines.append(f'| `{name}` | {n} |')
    Path(ns.out_md).write_text('\n'.join(lines)+'\n', encoding='utf-8')
    print(f'[OK] wrote {ns.out_md}')
    print(f'[OK] wrote {ns.out_csv}')

if __name__=='__main__':
    main()
