#!/usr/bin/env python3
"""Test round-by-round: parse once, truncate results, calculate next round."""

import sys
sys.path.insert(0, '.')

from swiss_calc.parser import fetch_tournament, fetch_url, parse_round_pairings
from swiss_calc.trf_generator import generate_trf
from swiss_calc.bbp_wrapper import call_bbp
import re

def norm(n):
    return re.sub(r'\s+', ' ', n.replace(',', '')).strip()

BASE = 'https://s1.chess-results.com/tnr1289471.aspx?lan=11'

print("=" * 60)
print("ТЕСТ: пошаговый расчёт всех туров")
print("=" * 60)

# Parse once — get full data with correct SNo, byes, forfeits
data = fetch_tournament(BASE)
total_rounds = data['current_round']
standings = data['standings']

print(f"Турнир: {data['name'][:60]}")
print(f"Сыграно туров: {total_rounds}")
print(f"Участников: {len(standings)}")

# Collect actual pairs for comparison
name_to_sno = {norm(s['name']): s['starting_sno'] for s in standings}
actual_pairs = {}
for rd in range(1, total_rounds + 1):
    html = fetch_url(f'{BASE}&art=2&rd={rd}&turdet=YES')
    games = parse_round_pairings(html, rd)
    for g in games:
        if g['white_sno'] == 0:
            g['white_sno'] = name_to_sno.get(norm(g['white_name']), 0)
        if g['black_sno'] == 0:
            g['black_sno'] = name_to_sno.get(norm(g['black_name']), 0)
    actual_pairs[rd] = games
    print(f"  Тур {rd}: {len(games)} пар")

print(f"\n{'='*60}")
print(f"ПОШАГОВЫЙ РАСЧЁТ")
print(f"{'='*60}")

overall_matched = 0
overall_total = 0

for next_rd in range(2, total_rounds + 1):
    completed = next_rd - 1
    
    # Truncate results to only first `completed` rounds
    truncated_standings = []
    for s in standings:
        full_results = s.get('results', [])
        full_orig = s.get('_orig_results', [])
        
        # Take results only up to round `completed`
        trunc_results = [r for r in full_results if r.get('round', 99) <= completed]
        trunc_orig = [r for r in full_orig if isinstance(r, dict) and r.get('round', 99) <= completed]
        
        points = sum(r['score'] for r in trunc_results)
        
        truncated_standings.append({
            'rank': s['rank'],
            'name': s['name'],
            'fed': s['fed'],
            'points': points,
            'starting_sno': s['starting_sno'],
            'rating': s.get('rating', 0),
            'results': trunc_results,
            '_orig_results': trunc_orig,
            'tb': s.get('tb', []),
        })
    
    truncated = {
        'name': data['name'],
        'num_rounds': total_rounds,
        'current_round': completed,
        'players': data['players'],
        'standings': truncated_standings,
    }
    
    trf = generate_trf(truncated, next_rd, name=data.get('name', 'Test'),
                       use_rank=True, initial_color_white=True)
    try:
        bbp_pairs, _ = call_bbp(trf)
    except Exception as e:
        print(f"  Тур {next_rd}: bbpPairings ОШИБКА — {e}")
        continue
    
    # Compare with actual
    calc_set = set()
    for w_sno, b_sno in bbp_pairs:
        if b_sno == 0 or w_sno == 0:
            continue
        calc_set.add((min(w_sno, b_sno), max(w_sno, b_sno)))
    
    real_set = set()
    for g in actual_pairs.get(next_rd, []):
        w, b = g['white_sno'], g['black_sno']
        if w == 0 or b == 0:
            continue
        # Only include completed games (not future pairings)
        if g.get('white_score') is not None:
            real_set.add((min(w, b), max(w, b)))
    
    matched = len(calc_set & real_set)
    total = len(real_set)
    if total == 0:
        print(f"  Тур {next_rd}: нет сыгранных пар для сравнения")
        continue
    
    pct = 100 * matched / total
    overall_matched += matched
    overall_total += total
    
    bar = '█' * int(pct / 5) + '░' * (20 - int(pct / 5))
    print(f"  Тур {next_rd}: {matched}/{total} совпадений [{bar}] {pct:.0f}%")

print(f"\n{'='*60}")
if overall_total > 0:
    print(f"ИТОГО: {overall_matched}/{overall_total} ({100*overall_matched/overall_total:.0f}%)")
else:
    print(f"ИТОГО: 0 пар")
print(f"{'='*60}")
