#!/usr/bin/env python3
"""Clasifica las divergencias repo<->D1 en estructurales y reales.

`verificar_paridad.py` dice CUANTAS referencias difieren, pero no de que tipo, y
solo imprime el detalle de las cuarenta primeras. La mayoria de las 431 no son
deriva de texto sino consecuencia de como esta repartido el contenido entre los
dos lados, y mezclarlas con las de verdad haria el informe inutil.

Clases estructurales (no hay que tocar nada):

  TITULO     el fichero del repo abre con el titulo del capitulo y en D1 ese
             titulo vive en `translation`, que aqui se compara aparte.
  COLOFON    «Thus end the Bhaktivedanta Purports…». El repo lo guarda en un
             fichero suelto por capitulo; D1 (y el impreso) lo pegan al final
             del ultimo verso. `repo_source` ya lo une al construir libros.
  VACIO      un lado no tiene texto que comparar.

Lo demas es DERIVA: los dos lados tienen texto y dicen cosas distintas. Ahi si
hay que mirar cual acierta, y el criterio es el de siempre — el impreso.

Uso: python3 clasificar_deriva.py [--limite 40]
"""
import difflib
import json
import pathlib
import re
import sys

HERE = pathlib.Path(__file__).resolve().parent
sys.path.insert(0, str(HERE))
from verificar_paridad import REPO, d1, pal, ref_de  # noqa: E402

COLOFON = re.compile(r'Thus end the Bhaktivedanta Purports', re.I)


def clase(dif):
    """dif = [(palabras_D1, palabras_repo), ...] de un solo par de bloques."""
    a, b = ' '.join(dif[0]), ' '.join(dif[1])
    if COLOFON.search(a) or COLOFON.search(b):
        return 'COLOFON'
    if not a or not b:
        # un lado vacio: titulo de capitulo del repo, o tramo que en D1 vive
        # en otra columna
        return 'TITULO' if (b and b == b.title()) or (a and a == a.title()) else 'VACIO'
    return 'DERIVA'


def main():
    lim = int(sys.argv[sys.argv.index('--limite') + 1]) if '--limite' in sys.argv else 60
    refs = json.loads((HERE / 'paridad_divergentes.json').read_text(encoding='utf-8'))
    fich = {x['ref']: x['file'] for x in refs}
    q = lambda s: "'" + s.replace("'", "''") + "'"
    todos = sorted(fich)
    cuenta = {'COLOFON': 0, 'TITULO': 0, 'VACIO': 0, 'DERIVA': 0}
    reales = []
    for i in range(0, len(todos), 40):
        lote = todos[i:i + 40]
        filas = {r['ref']: r for r in d1(
            "SELECT ref, COALESCE(translation,'') t, COALESCE(purport,'') p FROM verses "
            f"WHERE lang='en' AND ref IN ({','.join(q(x) for x in lote)})")}
        for r in lote:
            if r not in filas:
                continue
            a = pal((REPO / fich[r]).read_text(encoding='utf-8'))
            b = pal(filas[r]['t'] + '\n' + filas[r]['p'])
            sm = difflib.SequenceMatcher(None, b, a)
            for op, i1, i2, j1, j2 in sm.get_opcodes():
                if op == 'equal':
                    continue
                par = (b[i1:i2], a[j1:j2])
                c = clase(par)
                cuenta[c] += 1
                if c == 'DERIVA':
                    # se guardan seis palabras a cada lado: con la palabra sola
                    # el arbitraje contra el escaneo es indecidible («one» sale
                    # en todas las paginas), con contexto se resuelve
                    izq = ' '.join(a[max(0, j1 - 6):j1])
                    der = ' '.join(a[j2:j2 + 6])
                    reales.append({'ref': r, 'file': fich[r],
                                   'd1': ' '.join(par[0])[:110],
                                   'repo': ' '.join(par[1])[:110],
                                   'izq': izq, 'der': der})
        print(f'  {min(i+40, len(todos))}/{len(todos)}', end='\r', flush=True)

    print('\n  bloques por clase:', cuenta)
    print(f'  referencias con deriva real: {len({x["ref"] for x in reales})}')
    (HERE / 'deriva_real.json').write_text(
        json.dumps(reales, ensure_ascii=False, indent=1), encoding='utf-8')
    for x in reales[:lim]:
        print(f"  {x['ref']}\n      D1: {x['d1']!r}\n    repo: {x['repo']!r}")
    return 0


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