#!/usr/bin/env python3
"""Second-pass recall: recover approved corrections the EXACT block-match missed.
For each alignment block, find approved (veda->gold) pairs CONTAINED in the block
(afv substring of block-D1, afg substring of block-scan), locate the exact D1
sub-span of afv, and emit an edit. Uses FRESH D1 (post-pass1) so already-applied
ones are auto-skipped (D1 no longer has VEDA there). PREVIEW only.
"""
import json, re, difflib, sys, unicodedata, os
import sb_cc_apply as S
fold=S.fold; foldsp=S.foldsp; garbage=S.garbage; clean_md=S.clean_md; natkey=S.natkey
COLS=S.COLS
BASE=os.path.dirname(os.path.abspath(__file__))

def approved_actual(book):
    """list of (afv_folded, afg_folded, gold_actual) for sb*/cc_* sections."""
    cur=None; out=[]; pref='sb' if book=='sb' else 'cc'
    for line in open(os.path.join(BASE,'correcciones_LIMPIAS.md'),encoding='utf-8'):
        h=re.match(r'^#{2,3}\s+([A-Za-z_0-9]+)',line)
        if h: cur=h.group(1)
        m=re.search(r'buscar «(.+?)»\s*→\s*reemplazar por «(.+?)»',line)
        if not m: continue
        tag=re.search(r'\[([a-z_0-9]+)',line); sec=tag.group(1) if tag else cur
        if sec and sec.startswith(pref):
            out.append((foldsp(m.group(1)), foldsp(m.group(2)), m.group(2)))
    return out

def d1_tokens_pref(rows, ref_pref):
    toks=[]
    for r in sorted([x for x in rows if x['ref'].startswith(ref_pref)], key=lambda r:natkey(r['ref'])):
        for col in COLS:
            raw=r.get(col) or ''
            for m in re.finditer(r'\S+', raw):
                wc=clean_md(m.group(0))
                if wc.strip(): toks.append((wc,r['id'],col,m.start(),m.end(),r['ref']))
    return toks

def findspan(toks, afv):
    n=len(toks); target=afv
    for s in range(n):
        acc=fold(toks[s][0])
        if acc==target: return (s,s)
        for e in range(s+1,n):
            acc=acc+' '+fold(toks[e][0])
            if acc==target: return (s,e)
            if len(acc)>len(target): break
    return None

def run2(book, ref_pref, scan_keys, appr, rows, cellmap, exact_pairs):
    sw=S.scan_words_multi(scan_keys); dt=d1_tokens_pref(rows, ref_pref)
    if not dt: return []
    sm=difflib.SequenceMatcher(None,[fold(w) for w in sw],[fold(t[0]) for t in dt],autojunk=True)
    edits=[]; seen=set()
    for tag,i1,i2,j1,j2 in sm.get_opcodes():
        if tag=='equal': continue
        if (j2-j1)>40 or (i2-i1)>40: continue           # bound block size
        block=dt[j1:j2]; fveda=foldsp(' '.join(t[0] for t in block)); fgold=foldsp(' '.join(sw[i1:i2]))
        for afv,afg,gold in appr:
            if (afv,afg) in exact_pairs: continue        # pass1 territory
            if not afv or not afg: continue
            if afv in fveda and afg in fgold and not garbage(gold.split()):
                sp=findspan(block, afv)
                if not sp: continue
                s,e=sp; a,b=block[s],block[e]
                if a[1]!=b[1] or a[2]!=b[2]: continue     # same cell/col
                cid,col,cs,ce,ref=a[1],a[2],a[3],b[4],a[5]
                if foldsp((cellmap.get((cid,col),'') )[cs:ce])!=afv: continue
                key=(cid,col,cs,ce,gold)
                if key in seen: continue
                seen.add(key)
                edits.append({'id':cid,'col':col,'ref':ref,'cs':cs,'ce':ce,'veda':' '.join(t[0] for t in block[s:e+1]),'gold':gold})
    return edits

if __name__=='__main__':
    book=sys.argv[1]; only=sys.argv[2] if len(sys.argv)>2 else None
    d1=json.load(open('/tmp/d1_en2.json'))[0]['results']
    rows=[r for r in d1 if r['book']==book]
    cellmap={(r['id'],c):(r.get(c) or '') for r in rows for c in COLS}
    appr=approved_actual(book)
    exact=set((a,b) for a,b,_ in appr)  # placeholder; pass1 used exact (afv,afg)==block
    g=S.groups()
    total=[]
    for (bk,ref_pref),keys in sorted(g.items()):
        if bk!=book or (only and only not in ref_pref): continue
        e=run2(book,ref_pref,keys,appr,rows,cellmap,set())
        print(f'{ref_pref:12} pass2 candidates={len(e)}',flush=True)
        total+=e
    json.dump(total, open(f'/tmp/{book}_pass2.json','w'))
    print(f'TOTAL {book} pass2: {len(total)}',flush=True)
