#!/usr/bin/env python3
"""Limpia de los candidatos abiertos el TITULILLO que el OCR pego al texto.

El sintoma. Entre los candidatos que nunca se adjudicaron, la lectura del
escaneo no es texto del libro sino la cabecera de la pagina:

    repo: 'purusas or'      scan: 'purusahs or the sky beyond the universe 49'
    repo: 'nikolai'         scan: 'anti material worlds 35 nikolat'
    repo: ''                scan: 'xi xii krsna the supreme personality of godhead'

Ningun adjudicador puede decidir con eso delante, y aplicarlo verbatim produjo
en su dia 'Visakhapatnam' -> 'Visakha pat madhya lija ch 8 tana'.

Como se reconoce un titulillo sin listarlos a mano: es la primera o la ultima
linea de la pagina y se repite en muchas paginas del mismo libro. Se recogen del
OCR —no de los candidatos— y se quitan del campo `scan`.

Que sale de aqui, por candidato:
  RUIDO        quitando el titulillo, el escaneo dice lo mismo que el repo
  LIMPIO       queda una diferencia de verdad, ya adjudicable
  VACIO        el escaneo era SOLO titulillo

Uso: python3 quitar_titulillos.py [--aplicar]
"""
import json, re, sys, unicodedata, pathlib, collections

HERE = pathlib.Path(__file__).resolve().parent
SURYA = HERE / 'surya'
FECHA = '2026-08-11'


def sd(s):
    s = unicodedata.normalize('NFD', s or '')
    s = ''.join(c for c in s if unicodedata.category(c) != 'Mn')
    return ' '.join(re.sub(r'[^A-Za-z0-9]+', ' ', s.lower()).split())


def titulillos(libro, minimo=4):
    """Frases de cabecera o pie que se repiten en muchas paginas del libro."""
    cnt = collections.Counter()
    dirs = list((SURYA / libro).glob('*'))
    paginas = [p for d in dirs for p in d.glob('p*.surya.txt')]
    for f in paginas:
        lineas = [l.strip() for l in f.read_text(encoding='utf-8').splitlines() if l.strip()]
        for l in lineas[:2] + lineas[-2:]:
            n = sd(l)
            # sin los numeros de pagina, que cambian en cada hoja
            n = ' '.join(x for x in n.split() if not x.isdigit())
            if 2 <= len(n.split()) <= 9: cnt[n] += 1
    # los que se repiten mucho, y de mas largo a mas corto para que al quitar
    # no quede la cola del titulillo largo dentro del corto
    return sorted([k for k, v in cnt.items() if v >= minimo],
                  key=lambda x: -len(x)), len(paginas)


def limpia(s, heads):
    n = sd(s)
    for h in heads:
        if h and h in n: n = n.replace(h, ' ')
    # los numeros sueltos que quedan son la foliacion
    n = ' '.join(x for x in n.split() if not x.isdigit())
    return ' '.join(n.split())


def main():
    aplicar = '--aplicar' in sys.argv
    ab = [json.loads(l) for l in open(HERE / 'ledger.jsonl', encoding='utf-8')]
    ab = [x for x in ab if x.get('estado') == 'ABIERTO' and not x.get('razon')]
    print(f'candidatos nunca adjudicados: {len(ab)}')

    porlibro = collections.defaultdict(list)
    for x in ab: porlibro[x['libro']].append(x)

    res = collections.Counter(); limpios = []; ruido = []
    for libro, xs in sorted(porlibro.items()):
        if not (SURYA / libro).exists():
            res['sin OCR del libro'] += len(xs); continue
        heads, npag = titulillos(libro)
        tocados = 0
        for x in xs:
            r = sd(x.get('repo') or ''); s = sd(x.get('scan') or '')
            s2 = limpia(x.get('scan') or '', heads)
            if s2 != s: tocados += 1
            if r and s2 == r:
                res['RUIDO: era solo el titulillo'] += 1
                ruido.append({**x, 'scan_limpio': s2}); continue
            if not s2 and r:
                res['el escaneo era SOLO titulillo -> queda como supresion'] += 1
                limpios.append({**x, 'scan_limpio': ''}); continue
            if not s2 and not r:
                res['sin nada que adjudicar'] += 1
                ruido.append({**x, 'scan_limpio': ''}); continue
            res['LIMPIO: queda una diferencia real'] += 1
            limpios.append({**x, 'scan_limpio': s2})
        print(f'  {libro:42} {len(xs):4} casos | {len(heads):3} titulillos | {tocados:4} tocados')

    print()
    for k, v in res.most_common(): print(f'  {v:5}  {k}')

    json.dump(limpios, open(HERE / 'abiertos_limpios.json', 'w'), ensure_ascii=False, indent=1)
    print(f'\n-> abiertos_limpios.json ({len(limpios)})')
    if aplicar:
        with open(HERE / 'verdicts.jsonl', 'a') as fh:
            for x in ruido:
                fh.write(json.dumps({"repo": x.get('repo') or '', "scan": x.get('scan') or '',
                                     "estado": "RUIDO",
                                     "razon": "la lectura del escaneo era el TITULILLO de la pagina "
                                              "pegado al texto; quitandolo, el escaneo dice lo mismo "
                                              "que el repo",
                                     "fecha": FECHA}, ensure_ascii=False) + '\n')
        print(f'veredictos de RUIDO escritos: {len(ruido)}')
    else:
        print('(ensayo: anade --aplicar)')
    return 0


if __name__ == '__main__':
    sys.exit(main())
