#!/usr/bin/env python3
"""Reproduce the disclosed counts and illustrative calculations.

Run from any working directory. Default inputs are the CSV files next to this
script. No network access or third-party libraries are required. This is not a
product-selection, load-rating, installation or compliance program.
"""
from __future__ import annotations
import argparse
import csv
import json
import math
import sys
from pathlib import Path

KG_PER_LBM = 0.45359237
MPS_PER_MPH = 0.44704
N_PER_LBF = KG_PER_LBM * 9.80665
J_PER_FTLBF = N_PER_LBF * 0.3048

def read_csv(root: Path, name: str) -> list[dict[str, str]]:
    path = root / (name + '.csv')
    with path.open(encoding='utf-8-sig', newline='') as stream:
        rows = list(csv.DictReader(stream))
    if not rows:
        raise ValueError(f'No records in {path.name}')
    return rows

def equal(actual: float, expected: float, label: str, tolerance: float = 0.000002) -> None:
    if not math.isclose(actual, expected, rel_tol=1e-10, abs_tol=tolerance):
        raise ValueError(f'{label}: recorded {actual}, recalculated {expected}')

def calculate(root: Path) -> dict:
    models = read_csv(root, 'dock-bumper-combined-model-census')
    counts: dict[str, int] = {}
    for row in models:
        counts[row['manufacturer']] = counts.get(row['manufacturer'], 0) + 1
    if len(models) != 117 or len(counts) != 3:
        raise ValueError(f'Unexpected model denominator: {len(models)} records, {counts}')
    projections = sorted({float(row['projection_in']) for row in models})
    if len(projections) != 14:
        raise ValueError(f'Expected 14 distinct model projection fields, found {projections}')
    budget = read_csv(root, 'dock-bumper-projection-budget')
    for row in budget:
        for reach in (16, 18, 20):
            expected = reach-float(row['total_projection_in'])-float(row['assumed_trailer_floor_setback_in'])
            equal(float(row[f'effective_reach_{reach}_in_overlap_in']), expected, f'Geometry at {reach} in')
    energy_rows = read_csv(root, 'dock-bumper-impact-energy')
    energy_results = []
    for row in energy_rows:
        mass = float(row['assumed_moving_mass_lbm'])
        speed = float(row['assumed_speed_mph'])
        joules = 0.5*mass*KG_PER_LBM*(speed*MPS_PER_MPH)**2
        foot_pounds = joules/J_PER_FTLBF
        equal(float(row['kinetic_energy_joules']), joules, 'Kinetic energy, J')
        equal(float(row['kinetic_energy_ft_lbf']), foot_pounds, 'Kinetic energy, ft-lbf')
        if row['record_id'] in ('ENERGY-01', 'ENERGY-02'):
            force = float(row['conditional_average_resisting_force_lbf'])
            displacement = foot_pounds*12/force
            equal(float(row['assumed_or_back_calculated_stopping_displacement_in']), displacement, 'Back-calculated displacement')
        else:
            displacement = float(row['assumed_or_back_calculated_stopping_displacement_in'])
            force = foot_pounds*12/displacement
            equal(float(row['conditional_average_resisting_force_lbf']), force, 'Average resisting force')
        energy_results.append({'scenario': row['scenario'], 'joules': joules, 'ft_lbf': foot_pounds, 'average_force_lbf': force, 'displacement_in': displacement})
    prices = read_csv(root, 'dock-bumper-price-census')
    ideal = [float(r['published_price_usd']) for r in prices if r['brand'].startswith('Ideal Warehouse') and r['size_w_x_h_in'].replace(' ', '')=='16x10']
    if len(ideal) != 3:
        raise ValueError(f'Expected three Ideal Warehouse listings; found {len(ideal)}')
    ratio = max(ideal)/min(ideal)
    climate = read_csv(root, 'omaha-cold-exposure-layer')
    values = {float(r['value']) for r in climate}
    if not {15.2, 88.1, 72.9}.issubset(values):
        raise ValueError('Expected temperature-normal inputs were not present')
    claims = read_csv(root, 'dock-bumper-published-claims-audit')
    publishers = {r['publisher'] for r in claims}
    designations = [r for r in claims if r['test_method_published'].startswith('Designation ASTM')]
    if len(claims) != 12 or len(publishers) != 7 or len(designations) != 2:
        raise ValueError('Claim denominator or method-disclosure count does not match the page')
    return {
        'verification_date':'2026-09-12', 'model_count':len(models), 'manufacturers':counts,
        'distinct_model_projection_values_in':projections, 'distinct_model_projection_count':len(projections),
        'geometry_rows_checked':len(budget), 'geometry_note':'Hypothetical effective reach; no compliance assessment.',
        'pad_to_overall_difference_in':5.25-4.5, 'unallocated_difference_after_face_in':5.25-4.5-.375,
        'face_thickness_increase_percent':((.625/.375)-1)*100,
        'energy_calculations':energy_results,
        'force_at_0_75_vs_1_5_in_ratio':(1/.75)/(1/1.5),
        '75000_lbf_in_kN':75000*N_PER_LBF/1000, '168_kN_in_lbf':168000/N_PER_LBF,
        'six_inches_in_mm':6*25.4, 'ideal_advertised_price_ratio':ratio,
        'ideal_advertised_price_increase_percent':(ratio-1)*100,
        'normal_temperature_difference_F':round(88.1-15.2,1),
        'claim_records':len(claims), 'claim_publishers':len(publishers),
        'passages_with_printed_designation':len(designations), 'passages_without_named_method':len(claims)-len(designations),
        'limitations':'Arithmetic validates these inputs and transcription relationships, not the truth of marketing claims, suitability of a product or current stock.'
    }

def main() -> int:
    parser = argparse.ArgumentParser(description=__doc__)
    parser.add_argument('--data-dir', type=Path, default=Path(__file__).resolve().parent)
    args = parser.parse_args()
    try:
        print(json.dumps(calculate(args.data_dir), indent=2, ensure_ascii=False))
        return 0
    except (OSError, ValueError, KeyError) as exc:
        print(f'Check failed: {exc}', file=sys.stderr)
        return 1

if __name__=='__main__':
    raise SystemExit(main())
