#!/usr/bin/env python3
"""Lleva a D1 las divergencias donde el escaneo respalda al repo.

De donde salen. `arbitrar_deriva.py` cruza las 431 divergencias repo<->D1 con
el OCR del escaneo. Donde el escaneo dice lo mismo que el repo, el equivocado
es D1 y hay que empujarlo; son 621 bloques en 324 referencias.

Por que se puede empujar sin abrir 324 imagenes. El repo ya paso el diff de
Surya contra el escaneo, que esta a cero abiertos: cada divergencia entre repo
e impreso se adjudico una a una. Que el escaneo respalde al repo aqui no es una
segunda opinion floja, es la misma verificacion ya hecha.

Como se aplica. Con REPLACE sobre la frase EN SU CONTEXTO, no sobre la palabra
suelta: cambiar «one» por «he» a secas destrozaria el significado entero. Si el
contexto no aparece tal cual en D1, la fila se deja y se informa — mejor no
tocarla que tocarla mal.

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

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


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


def ejecutar(sql):
    f = HERE / '_deriva.sql'
    f.write_text(sql, encoding='utf-8')
    p = subprocess.run(['npx', 'wrangler', 'd1', 'execute', 'vedabase-search-db',
                        '--remote', '--file', str(f)], capture_output=True, text=True,
                       cwd=str(ASTRO),
                       env={**os.environ, 'CF_API_TOKEN': '', 'CLOUDFLARE_API_TOKEN': ''})
    f.unlink(missing_ok=True)
    if 'rows_written' not in p.stdout:
        print(p.stdout[-400:], p.stderr[-300:])
        return False
    return True


def main():
    aplicar = '--aplicar' in sys.argv
    d = json.loads((HERE / 'deriva_arbitrada.json').read_text(encoding='utf-8'))
    casos = [x for x in d if x['veredicto'] == 'D1 equivocado']
    stmts, saltados = [], 0
    for x in casos:
        # el contexto viene del repo, que es la forma buena; en D1 lo que hay
        # es el mismo contexto con la variante mala en medio
        # El ancho del contexto es un compromiso: cuanto mas largo, menos
        # riesgo de pegar en el sitio equivocado, pero mas probable que atraviese
        # una cursiva —el repo normaliza y las quita, D1 las conserva— y entonces
        # el REPLACE literal no casa y la fila se queda sin tocar. Se pasa dos
        # veces: primero ancho, luego estrecho para los que quedaron.
        ancho = int(sys.argv[sys.argv.index('--ancho') + 1]) if '--ancho' in sys.argv else 4
        izq = ' '.join(x.get('izq', '').split()[-ancho:])
        der = ' '.join(x.get('der', '').split()[:ancho]) if ancho else ''
        if not (izq or der):
            saltados += 1
            continue
        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:
            saltados += 1
            continue
        for col in ('purport', 'translation'):
            stmts.append(f"UPDATE verses SET {col} = REPLACE({col}, {q(viejo)}, {q(nuevo)}) "
                         f"WHERE ref={q(x['ref'])} AND lang='en';")
    print(f'  bloques a empujar: {len(casos) - saltados}   sin contexto utilizable: {saltados}')
    print(f'  sentencias: {len(stmts)}')
    if not aplicar:
        for s in stmts[:4]:
            print('   ', s[:150])
        print('  (ensayo: anade --aplicar)')
        return 0
    # en tandas: una sentencia gigante se lleva por delante el limite de D1
    ok = True
    for i in range(0, len(stmts), 150):
        ok &= ejecutar('\n'.join(stmts[i:i + 150]))
        print(f'   {min(i + 150, len(stmts))}/{len(stmts)}', end='\r', flush=True)
    print('\n  ' + ('empujado' if ok else 'FALLO en alguna tanda'))
    return 0 if ok else 1


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