"""Exact raw-deal suit census. Python 3.10+, standard library; run in any cwd."""
import csv
import io
import json
from collections import Counter, defaultdict
from itertools import combinations, product
from math import comb, prod
from pathlib import Path
import re

ROOT = Path(__file__).resolve().parent
SUITS = 'shdc'


def describe(cards):
    if not isinstance(cards, list) or len(cards) not in (4, 5, 6):
        raise ValueError('Supply four, five or six distinct standard cards.')
    if any(not isinstance(c, str) or not re.fullmatch('[2-9TJQKA][shdc]', c) for c in cards):
        raise ValueError('Cards use rank 2-9,T,J,Q,K,A and suit s,h,d,c.')
    if len(set(cards)) != len(cards):
        raise ValueError('Duplicate card.')
    counts = [sum(c[1] == s for c in cards) for s in SUITS]
    pairs = [list(p) for p in combinations(cards, 2) if p[0][1] == p[1][1]]
    return {'shape': '-'.join(str(c) for c in sorted(counts, reverse=True) if c),
            'same_suit_pairs': len(pairs),
            'flush_capable_suits': [s for s, c in zip(SUITS, counts) if c >= 2],
            'pair_witnesses': pairs}


def census(n):
    totals = defaultdict(int)
    for counts in product(range(n + 1), repeat=4):
        if sum(counts) == n:
            totals[tuple(sorted(counts, reverse=True))] += prod(comb(13, c) for c in counts)
    rows = []
    for counts, count in sorted(totals.items()):
        rows.append({'cards': n, 'shape': '-'.join(str(c) for c in counts if c),
                     'same_suit_pairs': sum(comb(c, 2) for c in counts),
                     'flush_capable_suits': sum(c >= 2 for c in counts),
                     'hands': count, 'total_hands': comb(52, n),
                     'percent': format(100 * count / comb(52, n), '.6f')})
    if sum(r['hands'] for r in rows) != comb(52, n):
        raise RuntimeError('Census total mismatch.')
    return rows


def main():
    rows = [r for n in (4, 5, 6) for r in census(n)]
    fixtures = json.loads((ROOT / 'examples.json').read_text(encoding='utf-8'))
    results = {'model': 'One uniformly random unordered hand from 52 distinct standard cards; no known cards, action filters, board or opponent condition.',
               'method': 'Enumerate labeled suit-count vectors and weight each by product of C(13,count). Exact integer counts; percentages rounded to six decimals.',
               'seed': None, 'random_samples': 0, 'rows': rows,
               'examples': [{'id': f['id'], 'cards': f['cards'], **describe(f['cards'])} for f in fixtures]}
    (ROOT / 'results.json').write_text(json.dumps(results, indent=2) + '\n', encoding='utf-8', newline='\n')
    out = io.StringIO(newline='')
    writer = csv.DictWriter(out, fieldnames=list(rows[0]), lineterminator='\n')
    writer.writeheader()
    writer.writerows(rows)
    (ROOT / 'suit-patterns.csv').write_text(out.getvalue(), encoding='utf-8', newline='\n')
    print(f'Generated {len(rows)} exact suit-shape rows and {len(fixtures)} constructed examples.')


if __name__ == '__main__':
    main()
