#!/usr/bin/env python3
"""Ищет повтор слов на стыке нескольких транскриптов и создаёт план склейки."""
from __future__ import annotations
import argparse, json, re
from difflib import SequenceMatcher
from pathlib import Path

def norm(s): return re.sub(r'[^a-zа-яё0-9]+','',s.lower())
def load(p):
    d=json.loads(Path(p).read_text(encoding='utf-8')); return d, d['words'] if isinstance(d,dict) else d

def overlap(a,b,max_words=50):
    at=a[-max_words:]; bh=b[:max_words]; A=[norm(x['word']) for x in at]; B=[norm(x['word']) for x in bh]
    best=None
    # Ищем совпадение, которое начинается близко к началу второго файла.
    for start_b in range(min(6,len(B))):
        sm=SequenceMatcher(None,A,B[start_b:],autojunk=False)
        for m in sm.get_matching_blocks():
            if m.size<3: continue
            score=m.size/max(1,len(B[:start_b+m.b+m.size]))
            cand=(m.size,score,len(a)-len(at)+m.a,start_b+m.b)
            if best is None or (cand[0],cand[1])>(best[0],best[1]): best=cand
    return best

def main():
    ap=argparse.ArgumentParser(); ap.add_argument('transcripts',nargs='+'); ap.add_argument('--out',default='stitch_plan.json')
    ap.add_argument('--min-overlap',type=int,default=3); args=ap.parse_args()
    loaded=[load(p) for p in args.transcripts]; sources=[]; joins=[]
    for i,(meta,words) in enumerate(loaded):
        src=meta.get('source',args.transcripts[i]); duration=float(meta.get('duration') or (words[-1]['end'] if words else 0))
        sources.append({'transcript':args.transcripts[i],'file':src,'in':0.0,'out':duration,'duration':duration})
    for i in range(len(loaded)-1):
        aw=loaded[i][1]; bw=loaded[i+1][1]; o=overlap(aw,bw)
        if o and o[0]>=args.min_overlap:
            size,score,ai,bi=o; end_b=bi+size-1
            trim=float(bw[end_b]['end']); sources[i+1]['in']=trim
            joins.append({'from':i,'to':i+1,'overlap_words':size,'score':round(score,3),
                          'text':' '.join(w['word'] for w in bw[bi:end_b+1]),'next_trim_start':trim,'needs_manual_review':score<0.6})
        else:
            joins.append({'from':i,'to':i+1,'overlap_words':0,'score':0,'next_trim_start':0.0,'needs_manual_review':True})
    expected=sum(max(0,s['out']-s['in']) for s in sources)
    plan={'version':'2.1','sources':sources,'joins':joins,'expected_duration':round(expected,3)}
    Path(args.out).write_text(json.dumps(plan,ensure_ascii=False,indent=2),encoding='utf-8')
    print(json.dumps(plan,ensure_ascii=False,indent=2))

if __name__=='__main__': main()
