#!/usr/bin/env python3
"""python3 validate_contract.py <lc> [<lc> ...] — اعتبارسنج ترجمه‌ی قرارداد (tr/<lc>.txt) در برابر src.txt"""
import re, sys, os, collections, unicodedata
HERE = os.path.dirname(os.path.abspath(__file__))
def load(p):
    rows = []
    for l in open(p, encoding='utf8').read().split('\n'):
        if l.strip() == '': continue
        i = l.find('|')
        rows.append((int(l[:i]) if l[:i].isdigit() else -1, l[i + 1:]))
    return rows
SRC = load(os.path.join(HERE, 'src.txt'))
PERS_ONLY = re.compile('[پچژگکی۰-۹ة]')   # پ چ ژ گ ک ی ارقام فارسی (ة مجاز در عربی نیست؛ پایین جدا)
PERS_DIG = re.compile('[۰-۹]')
SCRIPTS = {'ru': r'Ѐ-ӿ', 'uk': r'Ѐ-ӿ', 'he': r'֐-׿', 'ar': r'؀-ۿ', 'zh': r'一-鿿', 'ko': r'가-힯', 'hi': r'ऀ-ॿ'}
def norm_num(s):
    s = s.translate(str.maketrans('۰۱۲۳۴۵۶۷۸۹٠١٢٣٤٥٦٧٨٩', '01234567890123456789'))
    s = s.replace('٫', '.').replace('٬', ',')
    return s
def nums(s):
    s = re.sub(r'@@[A-Z]+@@|\{\{\w+\}\}|\{[nt]\}', ' ', s)
    # جداکننده‌ی اعشار/هزارگان (.,  nbsp) در زبان‌های مختلف فرق می‌کند؛ فقط رقم‌ها مقایسه می‌شوند
    return collections.Counter(re.sub(r'[.,\u00a0\u202f]', '', m) for m in re.findall(r'\d+(?:[.,\u00a0\u202f]\d+)*', norm_num(s)))
def toks(s, rx): return collections.Counter(re.findall(rx, s))
def check(lc):
    f = os.path.join(HERE, 'tr', lc + '.txt'); errs = []
    if not os.path.isfile(f): return ['missing file tr/%s.txt' % lc]
    rows = load(f)
    if len(rows) != len(SRC): errs.append('line count %d != %d' % (len(rows), len(SRC)))
    for k, ((i, t), (j, s)) in enumerate(zip(rows, SRC)):
        e = lambda m: errs.append('#%d %s' % (j, m))
        if i != j: e('id mismatch (got %d)' % i); continue
        if t.strip() == '': e('empty'); continue
        if t != t.strip(): e('leading/trailing space')
        for name, rx in (('token', r'@@[A-Z]+@@'), ('ref', r'\{\{\w+\}\}'), ('tpl', r'\{[nt]\}')):
            if toks(s, rx) != toks(t, rx): e('%s mismatch: src=%s tr=%s' % (name, dict(toks(s, rx)), dict(toks(t, rx))))
        if s.count('**') != t.count('**') or t.count('**') % 2: e('bold ** count src=%d tr=%d' % (s.count('**'), t.count('**')))
        if nums(s) != nums(t): e('numbers differ: src=%s tr=%s' % (dict(nums(s)), dict(nums(t))))
        for w in set(re.findall(r'\b(?:TraderPro|XAUUSD|USDT|USD|TXID|XAU)\b', s)):
            if w not in t: e('missing latin term ' + w)
        if lc != 'fa':
            if PERS_ONLY.search(t.replace('ة', '')): e('Persian letters/digits present: ' + ''.join(sorted(set(PERS_ONLY.findall(t))))[:20])
            letters = re.findall(r'[^\W\d_]', re.sub(r'@@[A-Z]+@@|\{\{\w+\}\}|TraderPro|XAUUSD', '', t))
            if len(letters) >= 25 and lc in SCRIPTS:
                ok = len(re.findall('[' + SCRIPTS[lc] + ']', ''.join(letters))) / len(letters)
                if ok < 0.55: e('script ratio %.2f too low for %s' % (ok, lc))
            if len(letters) >= 25 and lc not in SCRIPTS:
                if len(re.findall(r'[؀-ۿ֐-׿Ѐ-ӿ一-鿿가-힯ऀ-ॿ]', ''.join(letters))) > 0: e('foreign script in latin-language line')
            if len(s) > 40 and not (0.3 <= len(t) / len(s) <= 3.8): e('length ratio %.2f (src %d, tr %d) — truncated/padded?' % (len(t) / len(s), len(s), len(t)))
            if t == s and re.search(r'[؀-ۿ]', s): e('identical to Persian source')
        if '\t' in t or '\r' in t: e('tab/CR')
    return errs
if __name__ == '__main__':
    bad = 0
    for lc in sys.argv[1:]:
        e = check(lc)
        print('%s: %s' % (lc, 'OK' if not e else '%d errors' % len(e)))
        for x in e[:40]: print('   ', x)
        if len(e) > 40: print('    ... +%d more' % (len(e) - 40))
        bad += bool(e)
    sys.exit(1 if bad else 0)
