#!/usr/bin/env python3
"""Empuja a D1 las divergencias que el REPLACE literal no alcanza por el marcado.

El problema. `empujar_deriva_d1.py` compara el contexto del repo —normalizado,
sin cursivas— contra el texto de D1, que SI las lleva. En cuanto el contexto
atraviesa un `*termino*` o un `<em>`, el REPLACE literal no casa y la fila se
queda sin tocar. Quedaron 58 bloques asi.

La solucion. Traer el texto de D1, localizar el sitio con una expresion regular
que permita marcado ENTRE las palabras, sustituir en Python y devolver el campo
entero. Escribir el campo completo es mas invasivo que un REPLACE, asi que:

  - se exige que la expresion case UNA sola vez; con dos o mas, no se toca
  - se conserva el marcado que hubiera dentro del tramo sustituido cuando la
    palabra no cambia, porque solo se reemplaza la variante concreta
  - se comprueba que el resultado difiere del original antes de escribir

Uso:
    python3 empujar_deriva_marcado.py            # ensayo
    python3 empujar_deriva_marcado.py --aplicar
"""
import json
import os
import pathlib
import re
import subprocess
import sys

HERE = pathlib.Path(__file__).resolve().parent
ASTRO = HERE.parent.parent

# lo que puede aparecer ENTRE dos palabras sin ser parte de ninguna
ENTRE = r'(?:[\s]|\*|_|</?em>|</?i>|<br\s*/?>)+'
# Sin limite de palabra, «as» casa dentro de «brāhmaṇas». Me paso el 15-ago.
LIMITE = r'(?<![\w\u0100-\u1EFF])%s(?![\w\u0100-\u1EFF])'


def q(s):
    return "'" + str(s or '').replace("'", "''") + "'"


def d1(sql):
    p = subprocess.run(['npx', 'wrangler', 'd1', 'execute', 'vedabase-search-db', '--remote',
                        '--json', '--command', sql], capture_output=True, text=True,
                       cwd=str(ASTRO),
                       env={**os.environ, 'CF_API_TOKEN': '', 'CLOUDFLARE_API_TOKEN': ''})
    try:
        return json.loads(p.stdout)[0]['results']
    except Exception:
        return []


def patron(frase):
    """Palabras de `frase` separadas por marcado opcional."""
    return ENTRE.join(re.escape(w) for w in frase.split())


def main():
    aplicar = '--aplicar' in sys.argv
    casos = [x for x in json.loads((HERE / 'deriva_arbitrada.json').read_text(encoding='utf-8'))
             if x['veredicto'] == 'D1 equivocado']
    hechos = fallos = ambiguos = 0
    for x in casos:
        izq = ' '.join(x.get('izq', '').split()[-3:])
        der = ' '.join(x.get('der', '').split()[:3])
        viejo = ' '.join(y for y in (izq, x['d1'], der) if y)
        nuevo = ' '.join(y for y in (izq, x['repo'], der) if y)
        if viejo == nuevo:
            continue
        filas = d1(f"SELECT COALESCE(purport,'') p, COALESCE(translation,'') t FROM verses "
                   f"WHERE ref={q(x['ref'])} AND lang='en'")
        if not filas:
            fallos += 1
            continue
        for col, val in (('purport', filas[0]['p']), ('translation', filas[0]['t'])):
            m = list(re.finditer(patron(viejo), val))
            if len(m) != 1:
                if len(m) > 1:
                    ambiguos += 1
                continue
            tramo = m[0].group(0)
            # dentro del tramo, cambiar solo la variante mala por la buena
            dentro = re.sub(LIMITE % patron(x['d1']), lambda _: x['repo'], tramo, count=1)
            if dentro == tramo:
                continue
            resultado = val[:m[0].start()] + dentro + val[m[0].end():]
            print(f"  {x['ref']:18} {col:11} {x['d1'][:26]!r} -> {x['repo'][:26]!r}")
            hechos += 1
            if aplicar:
                d1(f"UPDATE verses SET {col} = {q(resultado)} "
                   f"WHERE ref={q(x['ref'])} AND lang='en';")
    print(f'\n  sustituidos: {hechos}   ambiguos (mas de un sitio, no tocados): {ambiguos}   '
          f'sin fila: {fallos}')
    if not aplicar:
        print('  (ensayo: anade --aplicar)')
    return 0


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