"""Контрасты токенов по WCAG 2.1. Читает proto/tokens.css, печатает пары и проходимость AA.
Запуск: python3 contrast.py            — проверка
        python3 contrast.py > contrast.md   — вывод в contrast.md
Правило: текст 4.5:1, границы и пиктограммы контролов 3:1."""
import re
import sys

TOKENS = {}
for m in re.finditer(r'(--[a-z0-9-]+):\s*(#[0-9A-Fa-f]{3,6})', open(sys.path[0] + '/../proto/tokens.css', encoding='utf-8').read()):
    TOKENS[m.group(1)] = m.group(2)


def lum(h):
    h = h.lstrip('#')
    if len(h) == 3:
        h = ''.join(c * 2 for c in h)
    ch = [int(h[i:i + 2], 16) / 255 for i in (0, 2, 4)]
    f = lambda c: c / 12.92 if c <= 0.03928 else ((c + 0.055) / 1.055) ** 2.4
    r, g, b = (f(c) for c in ch)
    return 0.2126 * r + 0.7152 * g + 0.0722 * b


def cr(a, b):
    x, y = sorted((lum(a), lum(b)), reverse=True)
    return (x + 0.05) / (y + 0.05)


# (передний, задний, что это, минимальная планка)
PAIRS = [
    ('--brand-600', '--n-000', 'белый текст на primary-кнопке', 4.5),
    ('--brand-700', '--n-000', 'белый текст на primary в hover', 4.5),
    ('--n-000', '--brand-600', 'текст на залитом primary', 4.5),
    ('--n-000', '--brand-700', 'текст на primary в hover', 4.5),
    ('--brand-text', '--n-000', 'ссылка и акцентный текст на белом', 4.5),
    ('--brand-text', '--brand-100', 'акцентный текст на выделении', 4.5),
    ('--brand-500', '--n-000', 'фокус-кольцо, полоса, маркер (не код)', 3.0),
    ('--n-800', '--n-000', 'основной текст', 4.5),
    ('--n-800', '--n-100', 'основной текст на серой зоне', 4.5),
    ('--n-600', '--n-000', 'вторичный текст и плейсхолдер', 4.5),
    ('--n-600', '--n-100', 'вторичный текст на серой зоне', 4.5),
    ('--n-400', '--n-000', 'граница контрола, пиктограмма (не код)', 3.0),
    ('--n-300', '--n-000', 'декоративный разделитель — порога нет', 0),
    ('--s-neutral-text', '--s-neutral-bg', 'чип: черновик, ожидает', 4.5),
    ('--s-success-text', '--s-success-bg', 'чип: подписан, активен', 4.5),
    ('--s-progress-text', '--s-progress-bg', 'чип: на согласовании', 4.5),
    ('--s-warning-text', '--s-warning-bg', 'чип: требуется действие, баннер срока', 4.5),
    ('--s-danger-text', '--s-danger-bg', 'чип: отказ, текст ошибки', 4.5),
    ('--s-danger-text', '--n-000', 'danger-текст на белом (кнопка отклонить)', 4.5),
    ('--s-muted-text', '--s-muted-bg', 'чип: аннулирован, завершён', 4.5),
]

rows, fails = [], 0
for fg, bg, what, need in PAIRS:
    ratio = cr(TOKENS[fg], TOKENS[bg])
    ok = '—' if need == 0 else ('AA' if ratio >= need else 'НЕ ПРОЙДЕН')
    if ok == 'НЕ ПРОЙДЕН':
        fails += 1
    rows.append((what, TOKENS[fg], TOKENS[bg], round(ratio, 2), f'{need}:1' if need else '—', ok))

print('# Контрасты токенов\n')
print('Посчитано `audit/contrast.py` по WCAG 2.1 relative luminance. Порог: текст 4.5:1, некодовые элементы 3:1.\n')
print('| Что | Текст | Фон | Контраст | Порог | Итог |')
print('|---|---|---|---|---|---|')
for what, f, b, r, need, ok in rows:
    print(f'| {what} | `{f}` | `{b}` | {r} | {need} | {ok} |')
print(f'\nПар с порогом: {len([r for r in rows if r[5] != "—"])}, непройденных: {fails}.')
sys.exit(1 if fails else 0)
