#!/usr/bin/env python3
"""Bounded public input-link reachability audit; no full media download or model call."""
import argparse,concurrent.futures,datetime,hashlib,json,pathlib,time,urllib.error,urllib.parse,urllib.request
ORIGIN='https://minimaxh3.studio'
def now():return datetime.datetime.now(datetime.timezone.utc).isoformat(timespec='seconds')
def probe(url):
    attempts=[]
    for method in ['HEAD','GET']:
        start=time.monotonic(); observed=now(); headers={'User-Agent':'MiniMaxH3-Public-Input-Audit/1.0','Accept':'*/*'}
        if method=='GET':headers['Range']='bytes=0-4095'
        req=urllib.request.Request(url,headers=headers,method=method)
        try:
            with urllib.request.urlopen(req,timeout=6) as response:
                # GET fallback reads at most 4096 bytes, even if server ignores Range.
                sample=response.read(4096) if method=='GET' else b''
                attempt={'observedAt':observed,'method':method,'status':response.status,'finalUrl':response.geturl(),'contentType':response.headers.get('Content-Type'),'contentLengthHeader':response.headers.get('Content-Length'),'contentRangeHeader':response.headers.get('Content-Range'),'sampleBytesRead':len(sample),'sampleSha256':hashlib.sha256(sample).hexdigest() if sample else None,'seconds':round(time.monotonic()-start,3)}
                attempts.append(attempt)
                return {'requestedUrl':url,'state':'http-reachable' if 200<=response.status<300 else 'unresolved','attempts':attempts,'interpretation':'HTTP status only; not a decode, viewing, rights or provider-compatibility check.'}
        except urllib.error.HTTPError as e:
            attempts.append({'observedAt':observed,'method':method,'status':e.code,'finalUrl':e.geturl(),'contentType':e.headers.get('Content-Type'),'sampleBytesRead':0,'seconds':round(time.monotonic()-start,3)})
            # Only bounded fallback for method-denied, forbidden or empty-body server responses.
            if method=='HEAD' and e.code in [403,405,501]:continue
            return {'requestedUrl':url,'state':'http-not-found' if e.code in [404,410] else 'unresolved','attempts':attempts,'interpretation':'An HTTP failure in this observation does not prove the original asset never existed.'}
        except Exception as e:
            attempts.append({'observedAt':observed,'method':method,'errorClass':type(e).__name__,'error':str(e)[:250],'sampleBytesRead':0,'seconds':round(time.monotonic()-start,3)})
            return {'requestedUrl':url,'state':'unresolved','attempts':attempts,'interpretation':'Network failure remains unknown; no availability or rights inference.'}
    return {'requestedUrl':url,'state':'unresolved','attempts':attempts}
def main():
    p=argparse.ArgumentParser();p.add_argument('--snapshot',type=pathlib.Path,default=pathlib.Path(__file__).with_name('selected-source-metadata.json'));p.add_argument('--out',type=pathlib.Path,required=True);args=p.parse_args()
    if args.out.exists():raise SystemExit('Refusing to overwrite an existing observation. Pick a new --out path.')
    snapshot=json.loads(args.snapshot.read_text());urls=set()
    for row in snapshot['records']:
        for ref in row['references']:
            for field in ['url','sourceUrl']:
                declared=ref.get(field)
                if declared:
                    url=urllib.parse.urljoin(ORIGIN,declared)
                    if urllib.parse.urlparse(url).scheme!='https':raise SystemExit('Only HTTPS public input URLs allowed')
                    urls.add(url)
    start=now()
    with concurrent.futures.ThreadPoolExecutor(max_workers=4) as pool:results=list(pool.map(probe,sorted(urls)))
    receipt={'schemaVersion':1,'startedAt':start,'completedAt':now(),'method':'HEAD; only 403/405/501 fallback GET Range bytes=0-4095 with a hard 4096-byte read cap; 6-second request timeout; 4 concurrent workers','sourceSnapshotSha256':hashlib.sha256(args.snapshot.read_bytes()).hexdigest(),'uniqueDeclaredInputUrls':len(urls),'results':results,'productionTaskRun':False,'modelOutputViewed':False,'mediaDecoded':False,'fullMediaDownloaded':False,'rightsVerified':False,'scriptSha256':hashlib.sha256(pathlib.Path(__file__).read_bytes()).hexdigest()}
    args.out.write_text(json.dumps(receipt,ensure_ascii=False,indent=2)+'\n')
    print(json.dumps({'urls':len(urls),'states':{state:sum(r['state']==state for r in results) for state in sorted({r['state'] for r in results})},'receiptSha256':hashlib.sha256(args.out.read_bytes()).hexdigest()}))
if __name__=='__main__':main()
