#!/usr/bin/env python3
"""Independent standard-library check of generated Schwarzschild horizon cases.
Uses pinned nominal conversions and adopted masses, not measured horizon sizes.
"""
import argparse,csv,hashlib,json,math,sys
from pathlib import Path
REFS=[
 ('c',299792458,'m/s','exact_definition','https://www.bipm.org/en/si-base-units/metre'),
 ('solar_gm_nominal',1.3271244e20,'m3/s2','exact_nominal_conversion','https://arxiv.org/abs/1510.07674'),
 ('au',149597870.7,'km','exact_definition','https://syrte.obspm.fr/IAU_resolutions/Sumredef_au.html'),
 ('mile',1.609344,'km','exact_conversion','https://www.nist.gov/pml/us-surveyfoot/revised-unit-conversion-factors')]
CASES=[('1','stellar-10',10,'hypothetical'),('2','stellar-20',20,'hypothetical'),('3','sagittarius-a',4000000,'rounded_comparison'),('4','m87',6500000000,'rounded_comparison')]
def require(test,message):
    if not test:raise ValueError(message)
def close(a,b):return math.isfinite(a) and math.isclose(a,b,rel_tol=2e-14,abs_tol=1e-12)
def analyze(folder):
    ref_file=folder/'reference-inputs.csv';data_file=folder/'generated-horizon-cases.csv'
    refs=list(csv.DictReader(ref_file.open(newline='',encoding='utf-8')));rows=list(csv.DictReader(data_file.open(newline='',encoding='utf-8')))
    require(len(refs)==4,'Expected four pinned reference rows');require(len(rows)==4,'Expected four generated cases');values={}
    for row,(key,value,unit,kind,url) in zip(refs,REFS):
        require(row['quantity']==key and float(row['reference_value'])==value and row['unit']==unit and row['reference_kind']==kind and row['source_url']==url,'Reference transcription mismatch');values[key]=value
    c=values['c'];gm=values['solar_gm_nominal'];au=values['au'];mile=values['mile'];coefficient=2*gm/(c*c)/1000;results=[]
    for row,(case,name,mass,status) in zip(rows,CASES):
        require(row['case_id']==case and row['case_name']==name and float(row['mass_nominal_solar'])==mass and row['mass_status']==status,'Case input mismatch')
        radius=2*(gm*mass)/(c*c)/1000;diameter=2*radius
        expected={'radius_km':radius,'diameter_km':diameter,'radius_mi':radius/mile,'diameter_mi':diameter/mile,'diameter_au':diameter/au,'diameter_ratio_to_case1':mass/10}
        for key,value in expected.items():require(close(float(row[key]),value),'Generated value mismatch: '+key)
        inverse=diameter/2*1000*c*c/(2*gm);require(close(inverse,mass),'Inverse-mass check failed')
        results.append(dict(case=case,name=name,massNominalSolar=mass,massStatus=status,radiusKm=radius,diameterKm=diameter,radiusMiles=radius/mile,diameterMiles=diameter/mile,diameterAu=diameter/au,diameterRatioToCase1=mass/10,recoveredMassNominalSolar=inverse))
    require(close(results[1]['diameterKm']/results[0]['diameterKm'],2),'Mass doubling check failed')
    return dict(methodVersion='1.0',resourceRelease='269',activity='https://darksciencedocs.com/scale-lab/#horizon-teaching',sourceReviewDate='2026-10-25',provenance='Four generated Schwarzschild comparisons from adopted nominal-solar masses. The 10/20 cases are hypothetical; Sgr A*/M87* inputs are rounded literature comparisons, not new mass or horizon measurements.',constants=dict(speedOfLightMS=c,nominalSolarGmM3S2=gm,auKm=au,kmPerInternationalMile=mile,radiusKmPerNominalSolarMass=coefficient,diameterKmPerNominalSolarMass=2*coefficient),cases=results,comparisons=dict(doublingMassDiameterFactor=2,doublingMassAreaFactor=4,sagittariusToStellar10=400000,m87ToSagittarius=1625,inverseFromRoundedDiameter118_130Km=118.130/(2*coefficient)),checks=dict(referenceSha256=hashlib.sha256(ref_file.read_bytes()).hexdigest(),generatedCasesSha256=hashlib.sha256(data_file.read_bytes()).hexdigest(),radiusDiameterUnitsRatiosAndInverseAgree=True),limits='Isolated nonrotating uncharged Schwarzschild model. Radius is areal/circumferential; D=2r_s is a size convention, not a ruler measurement through the interior. No spin, accretion-flow image, ray trace, observed shadow, mass inference, tidal survival or detection calculation. Exact nominal conversions do not remove uncertainty from adopted rounded masses. Stored digits support arithmetic, not measurement precision. No independent scientific review or formal curriculum alignment claimed.')
def main():
    p=argparse.ArgumentParser(description=__doc__);p.add_argument('--data-dir',type=Path,default=Path('.'));args=p.parse_args()
    try:print(json.dumps(analyze(args.data_dir),indent=2,allow_nan=False))
    except (OSError,ValueError,KeyError,ZeroDivisionError) as error:print('Verification failed: '+str(error),file=sys.stderr);return 1
    return 0
if __name__=='__main__':sys.exit(main())
