#!/usr/bin/env python3
"""Distill profitable fuzzing runs into attack archetypes.

For each profitable CSV:
1. Parse the action sequence
2. Consolidate consecutive same-direction trades
3. Consolidate recenters with same-direction floor movement
4. Reduce to minimal essential steps
5. Classify into archetypes
"""

import csv
import glob
import os
import sys
from collections import defaultdict

def parse_csv(path):
    """Parse a fuzzing CSV into a list of action dicts."""
    rows = []
    with open(path) as f:
        reader = csv.DictReader(f)
        for row in reader:
            rows.append(row)
    return rows

def get_pnl(rows):
    """Get trader PnL from INIT/FINAL rows."""
    init_eth = final_eth = None
    for row in rows:
        if row['action'] == 'INIT':
            init_eth = int(row['eth_balance'])
        if row['action'] == 'FINAL':
            final_eth = int(row['eth_balance'])
    if init_eth and final_eth:
        return (final_eth - init_eth) / 1e18
    return 0

def consolidate_sequence(rows):
    """Consolidate consecutive same-type actions into phases."""
    phases = []
    current_type = None
    current_amount = 0
    current_count = 0
    floor_start = None
    floor_end = None
    
    for row in rows:
        action = row['action']
        if action in ('INIT', 'FINAL', 'BUY_FAIL', 'SELL_FAIL', 'STAKE_FAIL', 'STAKE_SKIP', 'UNSTAKE_FAIL'):
            continue
        
        amount = int(row.get('amount', 0))
        floor_lower = int(row.get('floor_lower', 0))
        
        # Map to simplified types
        if action == 'BUY':
            simplified = 'BUY'
        elif action == 'SELL':
            simplified = 'SELL'
        elif action == 'RECENTER':
            simplified = 'RECENTER'
        elif action in ('STAKE', 'UNSTAKE'):
            simplified = action
        else:
            continue
        
        if simplified == current_type:
            current_amount += amount
            current_count += 1
            floor_end = floor_lower
        else:
            if current_type:
                phases.append({
                    'type': current_type,
                    'amount_eth': current_amount / 1e18 if current_type in ('BUY', 'SELL') else 0,
                    'count': current_count,
                    'floor_start': floor_start,
                    'floor_end': floor_end,
                    'floor_delta': (floor_end - floor_start) if floor_start and floor_end else 0
                })
            current_type = simplified
            current_amount = amount
            current_count = 1
            floor_start = floor_lower
            floor_end = floor_lower
    
    # Last phase
    if current_type:
        phases.append({
            'type': current_type,
            'amount_eth': current_amount / 1e18 if current_type in ('BUY', 'SELL') else 0,
            'count': current_count,
            'floor_start': floor_start,
            'floor_end': floor_end,
            'floor_delta': (floor_end - floor_start) if floor_start and floor_end else 0
        })
    
    return phases

def further_consolidate(phases):
    """Merge adjacent same-direction phases (e.g., BUY-RECENTER-BUY → BUY with recenter count)."""
    if not phases:
        return []
    
    result = []
    i = 0
    while i < len(phases):
        phase = dict(phases[i])
        
        # Look ahead for patterns like BUY-RECENTER-BUY
        while i + 2 < len(phases):
            next_phase = phases[i + 1]
            after_next = phases[i + 2]
            
            if next_phase['type'] == 'RECENTER' and after_next['type'] == phase['type']:
                # Merge: BUY + RECENTER + BUY → BUY (with embedded recenters)
                phase['amount_eth'] += after_next['amount_eth']
                phase['count'] += after_next['count']
                phase['floor_end'] = after_next['floor_end']
                phase['floor_delta'] = phase['floor_end'] - phase['floor_start'] if phase['floor_start'] and phase['floor_end'] else 0
                phase.setdefault('recenters', 0)
                phase['recenters'] += next_phase['count']
                i += 2
            else:
                break
        
        result.append(phase)
        i += 1
    
    return result

def classify_archetype(phases, pnl):
    """Classify a distilled sequence into an archetype."""
    # Count phase types
    types = [p['type'] for p in phases]
    buys = sum(1 for t in types if t == 'BUY')
    sells = sum(1 for t in types if t == 'SELL')
    recenters = sum(p['count'] for p in phases if p['type'] == 'RECENTER')
    total_recenters = recenters + sum(p.get('recenters', 0) for p in phases)
    
    buy_eth = sum(p['amount_eth'] for p in phases if p['type'] == 'BUY')
    sell_count = sum(p['count'] for p in phases if p['type'] == 'SELL')
    
    # Floor movement
    total_floor_delta = 0
    for p in phases:
        if p['floor_start'] and p['floor_end']:
            total_floor_delta += abs(p['floor_delta'])
    
    if total_recenters >= 15 and pnl > 100:
        return "HEAVY_RECENTER_DRAIN"
    elif sells > buys * 2:
        return "SELL_HEAVY_EXTRACT"
    elif total_recenters >= 10:
        return "RECENTER_FLOOR_WALK"
    elif pnl > 50:
        return "LARGE_EXTRACTION"
    else:
        return "MARGINAL_PROFIT"

def format_phase(p):
    """Format a phase for display."""
    t = p['type']
    if t in ('BUY', 'SELL'):
        recenters = p.get('recenters', 0)
        rec_str = f" ({recenters}R)" if recenters else ""
        return f"{t} {p['amount_eth']:.0f}ETH ×{p['count']}{rec_str}"
    elif t == 'RECENTER':
        return f"RECENTER ×{p['count']} (floor Δ{p['floor_delta']:+d})"
    elif t in ('STAKE', 'UNSTAKE'):
        return f"{t} ×{p['count']}"
    return f"{t}"

def main():
    csvs = sorted(glob.glob('analysis/fuzz-b*.csv'))
    print(f"Analyzing {len(csvs)} profitable CSVs...\n")
    
    archetypes = defaultdict(list)
    
    for path in csvs:
        rows = parse_csv(path)
        pnl = get_pnl(rows)
        if pnl <= 0:
            continue
        
        phases = consolidate_sequence(rows)
        distilled = further_consolidate(phases)
        archetype = classify_archetype(distilled, pnl)
        
        # Get batch info from filename
        name = os.path.basename(path)
        
        archetypes[archetype].append({
            'file': name,
            'pnl': pnl,
            'phases': distilled,
            'phase_count': len(distilled),
            'total_recenters': sum(p['count'] for p in distilled if p['type'] == 'RECENTER') + 
                              sum(p.get('recenters', 0) for p in distilled)
        })
    
    # Print results
    print("=" * 80)
    print("ATTACK ARCHETYPES")
    print("=" * 80)
    
    for archetype, runs in sorted(archetypes.items(), key=lambda x: -len(x[1])):
        print(f"\n### {archetype} ({len(runs)} runs)")
        avg_pnl = sum(r['pnl'] for r in runs) / len(runs)
        max_pnl = max(r['pnl'] for r in runs)
        avg_recenters = sum(r['total_recenters'] for r in runs) / len(runs)
        print(f"    Avg PnL: {avg_pnl:+.1f} ETH | Max: {max_pnl:+.1f} ETH | Avg recenters: {avg_recenters:.0f}")
        
        # Show the 3 most profitable examples distilled
        best = sorted(runs, key=lambda x: -x['pnl'])[:3]
        for run in best:
            print(f"\n    [{run['file']}] PnL={run['pnl']:+.1f} ETH ({run['phase_count']} phases, {run['total_recenters']} recenters)")
            for p in run['phases'][:15]:  # Show first 15 phases
                print(f"      → {format_phase(p)}")
            if len(run['phases']) > 15:
                print(f"      ... ({len(run['phases'])-15} more phases)")
    
    # Summary table
    print("\n" + "=" * 80)
    print("SUMMARY")
    print("=" * 80)
    print(f"\n{'Archetype':<25s} {'Count':>6s} {'Avg PnL':>10s} {'Max PnL':>10s} {'Avg Recenters':>14s}")
    print("-" * 70)
    total = 0
    for archetype, runs in sorted(archetypes.items(), key=lambda x: -len(x[1])):
        avg_pnl = sum(r['pnl'] for r in runs) / len(runs)
        max_pnl = max(r['pnl'] for r in runs)
        avg_rec = sum(r['total_recenters'] for r in runs) / len(runs)
        total += len(runs)
        print(f"{archetype:<25s} {len(runs):>6d} {avg_pnl:>+10.1f} {max_pnl:>+10.1f} {avg_rec:>14.0f}")
    print(f"\n{'TOTAL':<25s} {total:>6d}")

if __name__ == '__main__':
    main()
