#!/usr/bin/env python3
"""Validate evidence boundaries, not design quality or legal permission."""
import json, sys
from collections import Counter
from datetime import date
from urllib.parse import urlparse

def validate(data):
    errors=[]; seen=set(); counts=Counter()
    if data.get('schema_version') != 1: errors.append('schema_version must be 1')
    rows=data.get('records',[])
    if not rows: errors.append('records is empty')
    for r in rows:
        rid=r.get('id','<missing>')
        for k in ('id','name','genre_id','genre','url','locale','investigation_question','selection_type','evidence_label','evidence_url','checked_at','source_status','review_status','rights','code_reuse','media_reuse','interaction_tested'):
            if k not in r or r[k] in ('',None): errors.append(f'{rid}: missing {k}')
        if rid in seen: errors.append(f'{rid}: duplicate id')
        seen.add(rid); counts[r.get('genre_id')]+=1
        for key in ('url','evidence_url'):
            u=urlparse(r.get(key,''))
            if u.scheme != 'https' or not u.netloc or u.username or u.password: errors.append(f'{rid}: invalid {key}')
        for key,allowed in {'selection_type':{'candidate','award','standard'},'source_status':{'text_observed','limited_text','fetch_failed'},'review_status':{'candidate','reviewed','approved'},'rights':{'reference_only','original','licensed'},'code_reuse':{'not_cleared','original','cleared'},'media_reuse':{'not_cleared','original','cleared'}}.items():
            if r.get(key) not in allowed: errors.append(f'{rid}: invalid {key}')
        try:
            if date.fromisoformat(r['checked_at'])>date.today(): errors.append(f'{rid}: future check date')
        except (KeyError,ValueError): errors.append(f'{rid}: invalid date')
        if not isinstance(r.get('interaction_tested'),bool): errors.append(f'{rid}: interaction_tested must be boolean')
        if r.get('review_status') in ('reviewed','approved') and (not r.get('interaction_tested') or not r.get('review_evidence')):
            errors.append(f'{rid}: review requires interaction evidence')
        scores=r.get('scores')
        if scores is not None:
            axes={'task','information','accessibility','performance','expression','maintenance'}
            if set(scores)!=axes: errors.append(f'{rid}: incomplete scores')
            for k,s in scores.items():
                if not isinstance(s,dict) or type(s.get('value')) not in (int,float) or not 0<=s['value']<=5 or not s.get('evidence'): errors.append(f'{rid}: invalid score {k}')
        if r.get('review_status')=='approved' and (scores is None or not r.get('gates_passed')): errors.append(f'{rid}: approval requires scores and gates')
        if r.get('code_reuse')=='cleared' and not r.get('license_evidence'): errors.append(f'{rid}: cleared code needs license evidence')
    return errors,dict(sorted(counts.items()))

if __name__=='__main__':
    data=json.load(open(sys.argv[1],encoding='utf-8')); errors,counts=validate(data)
    print(json.dumps({'valid':not errors,'records':len(data.get('records',[])),'genre_counts':counts,'errors':errors},ensure_ascii=False,indent=2))
    sys.exit(bool(errors))
