"""Verify public quality choices and bounded CDN initialization requests."""
import argparse
import json
import re
import xml.etree.ElementTree as ET
from pathlib import Path
from urllib.error import HTTPError
from urllib.parse import urljoin,quote
from urllib.request import Request,urlopen


def tag(node): return node.tag.split('}')[-1]


def initialization(root,height,manifest_url):
    def descend(node,base,levels):
        bases=[e for e in node if tag(e)=='BaseURL']
        if bases: base=urljoin(base,(bases[0].text or '').strip())
        levels=levels+[node]
        if tag(node)=='Representation' and node.get('height')==str(height):
            target=None; byte_range=None
            for level in levels:
                for entry in level:
                    if tag(entry)=='SegmentTemplate' and entry.get('initialization'):
                        target=entry.get('initialization')
                    if tag(entry) in ('SegmentList','SegmentBase'):
                        for init in entry:
                            if tag(init)=='Initialization':
                                target=init.get('sourceURL',''); byte_range=init.get('range')
            if target is not None:
                target=target.replace('$RepresentationID$',node.get('id','')).replace('$Bandwidth$',node.get('bandwidth',''))
                if '$' not in target: return urljoin(base,target),byte_range
        for child in node:
            if tag(child) in ('Period','AdaptationSet','Representation'):
                found=descend(child,base,levels)
                if found: return found
        return None
    return descend(root,manifest_url,[])


def main():
    parser=argparse.ArgumentParser(); parser.add_argument('--link-file',required=True); parser.add_argument('--output',default='quality-results.json'); args=parser.parse_args()
    link=next(x for x in Path(args.link_file).read_text().splitlines() if x.startswith('https://') and x.endswith('/manifest.json')); base=link[:-len('/manifest.json')]
    def get(route):
        with urlopen(base+route,timeout=90) as response: return json.load(response)
    report={'version':get('/manifest.json')['version'],'checks':[]}
    search=get('/catalog/movie/top/search='+quote('Heart of the Beast',safe='')+'.json')['metas']
    matches=[item for item in search if item.get('name','').casefold()=='heart of the beast' and '2026' in str(item.get('year',item.get('releaseInfo','')))]
    if not matches: matches=[item for item in search if item.get('name','').casefold()=='heart of the beast']
    cases=[('movie','tt0816692','Interstellar'),('series','tt1475582:1:1','Sherlock S01E01')]
    if matches: cases.insert(0,('movie',matches[0]['id'],'Heart of the Beast'))
    for kind,ident,name in cases:
        row={'title':name,'choices':[]}
        streams=get('/stream/'+kind+'/'+ident+'.json')['streams']
        assert streams and all(s.get('name','').startswith('MovieBox Auto') for s in streams),'Non-Auto source advertised'
        for source in streams:
            match=re.search(r' (\d+)p$',source.get('name',''))
            if not match:
                row['choices'].append({'name':source.get('name'),'forced':False}); continue
            height=int(match[1]); headers=dict(source.get('behaviorHints',{}).get('proxyHeaders',{}).get('request',{}))
            adaptive='/auto' in source['url']
            with urlopen(Request(source['url'],headers=headers),timeout=45) as response:
                assert response.headers.get_content_type()=='application/dash+xml'
                raw=response.read(2*1024*1024+1)
            root=ET.fromstring(raw)
            heights=[int(e.get('height')) for e in root.iter() if tag(e)=='Representation' and e.get('height')]
            audio=[e for e in root.iter() if tag(e)=='AdaptationSet' and (e.get('contentType')=='audio' or e.get('mimeType','').startswith('audio/') or any(x.get('mimeType','').startswith('audio/') for x in e))]
            assert heights and (height in heights and any(h<height for h in heights) and max(heights)==height if adaptive else set(heights)=={height}),'Selected manifest has incorrect resolutions'
            assert audio,'Audio missing from selected manifest'
            choice={'name':source['name'],'videoHeights':sorted(set(heights)),'audioPreserved':True,'manifestHTTP':200}
            init=initialization(root,height,source['url'])
            if init and height in (1080,720):
                target,byte_range=init
                assert '/moviebox/' not in target,'Segment URL incorrectly points to add-on'
                headers['Range']='bytes='+byte_range if byte_range else 'bytes=0-8191'
                try:
                    with urlopen(Request(target,headers=headers),timeout=20) as response:
                        data=response.read(8192); choice['cdnInitHTTP']=response.status; choice['initBytesRead']=len(data)
                except HTTPError as error: choice['cdnInitHTTP']=error.code
            row['choices'].append(choice)
        report['checks'].append(row); print(json.dumps(row),flush=True)
    Path(args.output).write_text(json.dumps(report,indent=2))


if __name__=='__main__': main()
