"""Strict plain-text subset of SRT to WebVTT, not a universal converter."""
import re,json,html
SAMPLE='1\n00:00:01,250 --> 00:00:03,000\nکتاب، روی میز آبی است.\n\n2\n00:00:03,000 --> 00:00:05,500\nلطفاً صفحهٔ دوم را باز کنید.\n'
TIMING=re.compile(r'([0-9]{2,}):([0-5][0-9]):([0-5][0-9]),([0-9]{3}) --> ([0-9]{2,}):([0-5][0-9]):([0-5][0-9]),([0-9]{3})')
def convert(raw):
    normalized=raw.removeprefix('\ufeff').replace('\r\n','\n').replace('\r','\n').strip()
    if not normalized:raise ValueError('nonempty SRT required')
    cues=[];previous_start=-1;ids=set()
    for block in re.split(r'\n[ \t]*\n',normalized):
        lines=block.split('\n')
        if len(lines)<3 or not re.fullmatch(r'[0-9]+',lines[0]):raise ValueError('numeric id and nonempty payload required')
        ident=lines[0]
        if ident in ids:raise ValueError('duplicate id rejected by this contract')
        ids.add(ident);match=TIMING.fullmatch(lines[1])
        if not match:raise ValueError('strict HH:MM:SS,mmm timing without settings required')
        v=list(map(int,match.groups()));start=((v[0]*60+v[1])*60+v[2])*1000+v[3];end=((v[4]*60+v[5])*60+v[6])*1000+v[7]
        if end<=start or start<previous_start:raise ValueError('positive duration and ordered starts required')
        previous_start=start;payload='\n'.join(lines[2:])
        if not payload.strip() or any(c in payload for c in '<>') or '-->' in payload:raise ValueError('plain text only, no markup or arrows')
        # Plain text in SRT is encoded for VTT cue-text parsing.
        encoded_payload=payload.replace('&','&amp;')
        cues.append(ident+'\n'+lines[1].replace(',','.')+'\n'+encoded_payload)
    return 'WEBVTT\n\n'+'\n\n'.join(cues)+'\n'
if __name__=='__main__':
    out=convert(SAMPLE)
    assert out.startswith('WEBVTT\n\n1\n00:00:01.250') and 'کتاب، روی میز آبی است.' in out
    assert convert('\ufeff'+SAMPLE.replace('\n','\r\n'))==out
    for plain in ['الف & ب','الف &amp; ب','الف &#65; ب']:
        encoded=convert('1\n00:00:01,000 --> 00:00:02,000\n'+plain).split('\n')[4]
        assert html.unescape(encoded)==plain
    assert 'الف &amp;amp; ب' in convert('1\n00:00:01,000 --> 00:00:02,000\nالف &amp; ب')
    bad=[SAMPLE.replace('00:00:03,000','00:00:00,000',1),SAMPLE.replace('00:00:01,250','00:61:01,250'),SAMPLE.replace('کتاب،','<b>کتاب</b>،'),SAMPLE.replace('\n2\n','\n1\n')]
    for text in bad:
        try:convert(text)
        except ValueError:continue
        raise AssertionError('invalid fixture accepted')
    print(out)
