#!/usr/bin/env python3
"""Devuelve al repo el texto que el impreso trae y la edicion digital perdio.

La operacion contraria a `aplicar_supresion.py`. Aqui no sobra nada: FALTA. El
adjudicador ha leido la pagina, ha transcrito el pasaje con sus diacriticos
(`texto_impreso`) y ha copiado del fichero la frase que lo precede (`donde`).
Insertar es mas peligroso que borrar —un texto inventado se queda ahi como si
fuera de Prabhupada—, asi que solo se escribe lo transcrito, nunca lo deducido.

Guardarrailes:
  - `donde` tiene que aparecer UNA sola vez en el fichero. Si no, no hay
    posicion y se aparta.
  - NO DUPLICAR. Si el texto ya esta justo detras (o muy cerca), se salta: es la
    firma de una segunda pasada sobre lo ya aplicado.
  - DIACRITICOS. Una transcripcion sin un solo diacritico en un pasaje sanscrito
    es sospechosa de estar hecha de memoria; se avisa.
  - La costura respeta la puntuacion: si lo insertado empieza por un signo
    (parentesis, raya, coma) no se mete espacio delante.

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

HERE = pathlib.Path(__file__).resolve().parent
REPO = pathlib.Path('/Users/jaganat/git_projects/vedabase-original')
FECHA = '2026-08-11'
SIN_ESPACIO_ANTES = '.,;:!?)]}»”'


def sd(s):
    s = unicodedata.normalize('NFD', s or '')
    return ''.join(c for c in s if unicodedata.category(c) != 'Mn').lower()


def main():
    aplicar = '--aplicar' in sys.argv
    casos = json.load(open(HERE / 'huecos_confirmados.json', encoding='utf-8'))
    print(f'huecos confirmados sobre la imagen: {len(casos)}')

    res = collections.Counter(); hechas = []; apartados = []
    porfich = collections.defaultdict(list)
    for c in casos: porfich[c['file']].append(c)

    for fich, lista in sorted(porfich.items()):
        p = REPO / fich
        if not p.exists():
            res['sin fichero'] += len(lista); continue
        txt = p.read_text(encoding='utf-8')
        pend = []
        for c in lista:
            donde, nuevo = c.get('donde', '').strip(), c.get('texto_impreso', '').strip()
            if not donde or not nuevo:
                res['sin ancla o sin transcripcion'] += 1
                apartados.append({**c, 'motivo': 'faltan datos'}); continue
            ms = [m for m in re.finditer(re.escape(donde), txt)]
            if len(ms) != 1:
                res[f'el ancla aparece {len(ms)} veces'] += 1
                apartados.append({**c, 'motivo': f'ancla en {len(ms)} sitios'}); continue
            fin = ms[0].end()
            # YA INSERTADO, o casi. Mirar por delante sin diacriticos.
            cola = sd(txt[fin:fin + len(nuevo) * 2 + 60])
            if sd(nuevo)[:30] in cola:
                res['ya estaba puesto'] += 1; continue
            # DUPLICACION POR VARIANTE. Comprobar el literal no basta: al meter
            # «for the reason that He is above the influence of material nature»
            # en sb/3/31/14, lo que seguia era «, for He is above the influence
            # of material nature» —la misma frase con otro arranque— y quedo
            # dicha dos veces. Se compara el NUCLEO, sin las primeras palabras.
            nucleo = ' '.join(sd(nuevo).split()[-6:])
            if len(nucleo.split()) >= 4 and nucleo in cola:
                res['lo que sigue ya dice lo mismo con otras palabras'] += 1
                apartados.append({**c, 'motivo': 'duplicaria la frase siguiente'}); continue
            pend.append((fin, nuevo, c))

        for fin, nuevo, c in sorted(pend, key=lambda y: -y[0]):
            # El espacio se decide por el caracter ANTERIOR al punto de
            # insercion, no por el posterior. Mirando el posterior salia
            # 'and' + 'clouds evaporate' pegado ('andclouds'), porque detras de
            # la coma del ancla ya venia un espacio y se interpretaba como que
            # no hacia falta ninguno.
            antes = txt[fin - 1:fin]
            sep = '' if (antes in ' ([{«“' or nuevo[:1] in SIN_ESPACIO_ANTES
                         or nuevo[:1] == '—') else ' '
            # y un espacio DETRAS si lo que sigue es palabra pegada
            cola = '' if txt[fin:fin + 1] in ' \n' or txt[fin:fin + 1] in SIN_ESPACIO_ANTES \
                      or nuevo[-1:] in ' \n' else ' '
            txt = txt[:fin] + sep + nuevo + cola + txt[fin:]
            hechas.append({'file': c['file'], 'insertado': nuevo,
                           'tras': c['donde'][:90], 'nota': c.get('nota', '')[:240]})
        if aplicar and pend: p.write_text(txt, encoding='utf-8')

    res['INSERTADO'] = len(hechas)
    print()
    for k, v in res.most_common(): print(f'  {v:5}  {k}')
    print()
    for h in hechas:
        print(f"  {h['file'].split('/')[-1]:24} + {h['insertado'][:60]!r}")

    json.dump(hechas, open(HERE / 'huecos_aplicados.json', 'w'), ensure_ascii=False, indent=1)
    json.dump(apartados, open(HERE / 'huecos_apartados.json', 'w'), ensure_ascii=False, indent=1)
    if aplicar:
        with open(HERE / 'verdicts.jsonl', 'a') as fh:
            for h in hechas:
                fh.write(json.dumps({"repo": "", "scan": h['insertado'][:120].lower(),
                                     "estado": "VERIFICADO",
                                     "razon": f"HUECO: el impreso lo trae y el repo no. {h['nota']}",
                                     "fecha": FECHA}, ensure_ascii=False) + '\n')
        print(f'\nAPLICADO: {len(hechas)} | apartados: {len(apartados)}')
    else:
        print('\n(ensayo: anade --aplicar)')
    return 0


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