#!/usr/bin/env python3
"""Repone en D1 los tramos de texto que el repo trae y D1 no.

De donde salen. `paridad_completa.py` marca las referencias donde el repo tiene
palabras sin contraparte en D1. Al alinear los dos textos se ve que no son
palabras sueltas cambiadas de sitio sino tramos que faltan:

    cc/madhya/9/1    falta «Herein it is stated that the Lord delivered the
                     Gajendra, the elephant who was being attacked by crocodiles»
    cc/madhya/9/131  D1 dice «attains Him» y el repo «attains the Lord and gets
                     to know Him as He is known»

Como se coloca. El diff da el contexto en palabras normalizadas, pero el campo
de D1 lleva marcado y puntuacion, asi que el contexto no casa literal. Se
construye un patron que admite marcado y signos ENTRE las palabras y se exige
que aparezca UNA sola vez; con dos o mas no se toca, porque colocar un tramo en
el sitio equivocado es peor que dejarlo fuera.

El tramo que se inserta se toma del .md del repo con su marcado original, no de
la version normalizada del diff: si no, se perderian las cursivas.

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

HERE = pathlib.Path(__file__).resolve().parent
ASTRO = HERE.parent.parent
REPO = pathlib.Path('/Users/jaganat/git_projects/vedabase-original')
sys.path.insert(0, str(HERE))
from paridad_completa import pal  # noqa: E402

# lo que puede aparecer entre dos palabras sin ser parte de ninguna
ENTRE = r'(?:[\s\*_,;:.!?()\[\]"\'’‘“”—–-]|</?em>|</?i>|<br\s*/?>|\\)+'
INDIO = re.compile(r'[ऀ-ॿঀ-৿]')


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': ''})
    if p.returncode != 0:
        return None
    try:
        return json.loads(p.stdout)[0]['results']
    except Exception:
        return None


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


def tramo_con_marcado(texto, palabras):
    """El tramo del .md que corresponde a esas palabras, con su marcado."""
    if not palabras:
        return ''
    pat = ENTRE.join(re.escape(w) for w in palabras)
    m = re.search(pat, texto)
    return m.group(0) if m else ' '.join(palabras)


def main():
    aplicar = '--aplicar' in sys.argv
    grupos = json.loads((HERE / 'paridad_clasificada.json').read_text(encoding='utf-8'))
    casos = grupos.get('texto solo en el repo', [])
    hechos = ambiguos = fallos = 0
    for x in casos:
        ref, fich = x['ref'], x['file']
        md = (REPO / fich).read_text(encoding='utf-8')
        filas = d1(f"SELECT COALESCE(verse_text,'') v, COALESCE(devanagari,'') d, "
                   f"COALESCE(synonyms,'') s, COALESCE(translation,'') t, "
                   f"COALESCE(purport,'') p FROM verses WHERE ref={q(ref)} AND lang='en'")
        if not filas:
            fallos += 1
            continue
        fila = filas[0]
        a = pal(md)
        b = pal(' '.join((fila['v'], fila['d'], fila['s'], fila['t'], fila['p'])))
        sm = difflib.SequenceMatcher(None, b, a)
        for op, i1, i2, j1, j2 in sm.get_opcodes():
            if op == 'equal' or j1 == j2:
                continue
            falta = a[j1:j2]
            if INDIO.search(' '.join(falta)) or not falta:
                continue
            izq = b[max(0, i1 - 6):i1]
            der = b[i2:i2 + 3]
            if len(izq) < 3:
                ambiguos += 1
                continue
            inserto = tramo_con_marcado(md, falta)
            colocado = False
            for col in ('purport', 'translation'):
                val = fila[col[0]]
                pat = ENTRE.join(re.escape(w) for w in izq)
                m = [z for z in re.finditer(pat, val)]
                if len(m) != 1:
                    continue
                nuevo = val[:m[0].end()] + ' ' + inserto + val[m[0].end():]
                print(f"  {ref:20} {col:11} + {inserto[:60]!r}")
                if aplicar:
                    d1(f"UPDATE verses SET {col}={q(nuevo)} WHERE ref={q(ref)} AND lang='en';")
                hechos += 1
                colocado = True
                break
            if not colocado:
                ambiguos += 1
                print(f"  {ref:20} sin sitio inequivoco para {' '.join(falta)[:50]!r}")
    print(f'\n  repuestos: {hechos}   sin sitio: {ambiguos}   sin fila: {fallos}')
    if not aplicar:
        print('  (ensayo: anade --aplicar)')
    return 0


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