"""System audit: static support/floor pressure and explicitly partial dynamics.

No hardware is enabled and no previous CAD/build scripts are imported.
"""
import csv
import hashlib
import json
import math
import sys
from pathlib import Path

sys.stdout.reconfigure(encoding="utf-8")
HERE = Path(__file__).resolve().parent
DEVICE = HERE.parent
G = 9.80665


def read(p):
    return json.loads(p.read_text(encoding="utf-8"))


previous = read(DEVICE / "pneumatic_rebaseline_v0_32/calculation.json")
wheel = read(DEVICE / "pneumatic_wheel_selection_v0_33/wheel_brief.json")
for name, sha in previous["input_sha256"].items():
    assert hashlib.sha256((DEVICE / "common_support_v0_31" / name).read_bytes()).hexdigest() == sha
M = previous["baseline_reference"]["total_mass_kg"]
W = M * G
foot_area = 0.15 * 0.15
user_floor_uniform_kg_m2 = 500
floor_uniform_pressure_Pa = user_floor_uniform_kg_m2 * G
central = previous["central_cases_Fx_equals_N"][1]
max_pose = max(previous["current_first_stage_pose_cases"], key=lambda c: max(c["foot_normal_equal_stiffness_N"]))
max_force = max(max_pose["foot_normal_equal_stiffness_N"])
floor = dict(user_reported_uniform_load_kg_m2=user_floor_uniform_kg_m2,
             equivalent_uniform_pressure_Pa=floor_uniform_pressure_Pa,
             verified_local_floor_capacity=None, verified_steel_sheet_thickness_mm=None,
             verified_underfloor_support=None,
             reference_foot_size_mm=[150, 150], all_four_nominal_foot_area_m2=4 * foot_area,
             airborne_mean_foot_pressure_Pa=W / (4 * foot_area),
             airborne_mean_foot_equivalent_kg_m2=M / (4 * foot_area),
             central_N100_Fx100_max_foot_force_N=max(central["foot_normal_equal_stiffness_N"]),
             central_max_foot_pressure_Pa=max(central["foot_normal_equal_stiffness_N"]) / foot_area,
             reference_pose_max_foot_force_N=max_force,
             reference_pose_max_pressure_Pa=max_force / foot_area,
             reference_pose_max_equivalent_kg_m2=max_force / foot_area / G,
             arithmetic_spreader_square_side_mm=math.sqrt(max_force / floor_uniform_pressure_Pa) * 1000,
             spreader_is_released_design=False,
             spreader_missing_checks=["own mass", "plate flexure", "actual contact", "floor supports", "transient and operator loads"],
             max_foot_pose=max_pose)

# Construct a sufficient longitudinal-only shear distribution. It balances
# net Fx and the yaw torque Fx*Y; it is NOT a minimum-friction optimization.
yaw_cases = []
b = 375
feet = previous["baseline_reference"]["feet_centres_xy_mm"]
for c in previous["current_first_stage_pose_cases"]:
    F, y = c["Fx_N"], c["manual_Y_mm"]
    group_r = {s: sum(r for (_, yy), r in zip(feet, c["foot_normal_equal_stiffness_N"]) if yy * s > 0) for s in [-1, 1]}
    demand = {s: abs(F * (1 + s * y / b) / 2) for s in [-1, 1]}
    required = max(demand[s] / group_r[s] for s in [-1, 1])
    shears = []
    for (_, yy), ri in zip(feet, c["foot_normal_equal_stiffness_N"]):
        s = 1 if yy > 0 else -1
        shears.append(-F * (1 + s * y / b) / 2 * ri / group_r[s])
    assert abs(sum(shears) + F) < 1e-8
    assert abs(sum(-yy * tx for (_, yy), tx in zip(feet, shears)) - y * F) < 1e-7
    yaw_cases.append(dict(N_N=c["N_N"], Fx_N=F, Y_mm=y, Z_mm=c["lift_Z_mm"],
                          external_yaw_torque_Nm=-y * F / 1000,
                          sufficient_uniform_foot_mu=required,
                          sufficient_mu_with_assumed_1_5_reserve=1.5 * required,
                          foot_shear_X_N=shears))
worst_yaw = max(yaw_cases, key=lambda c: c["sufficient_mu_with_assumed_1_5_reserve"])

R = wheel["wheel"]["nominal_design_diameter_mm"] / 2000
omega = 60 / 3.6 / R
i = 1.5
# Actual local source table: SYD143-0310L30, unbraked rotor J=6.69*10^-4.
# Wheel inertia is unknown. Values below are scenarios, not measured values.
Jm = 6.69e-4
dynamics = []
for Jw in [0.005, 0.01, 0.02]:
    Je = Jw + i * i * Jm  # energy / drive-torque inertia at the wheel
    Jh = Jw + i * Jm  # physical angular momentum derivative, parallel same-direction axes
    for ramp_s in [0.25, 1, 3]:
        alpha = omega / ramp_s
        dynamics.append(dict(assumed_wheel_inertia_kg_m2=Jw,
                             motor_rotor_reference_kg_m2=Jm, ratio=i, ramp_s=ramp_s,
                             wheel_alpha_rad_s2=alpha,
                             wheel_plus_motor_energy_inertia_kg_m2=Je,
                             wheel_plus_motor_angular_momentum_coefficient_kg_m2=Jh,
                             airborne_frame_reaction_torque_magnitude_Nm=Jh * alpha,
                             wheel_plus_motor_kinetic_energy_J=0.5 * Je * omega * omega,
                             assumed_drive_efficiency=0.9,
                             airborne_motor_acceleration_torque_Nm=Je * alpha / (0.9 * i),
                             motor_torque_if_simultaneous_Fx100_Nm=(Je * alpha + 100 * R) / (0.9 * i),
                             partial_model=True,
                             omitted_inertia_and_losses=["input/output pulley separate inertia", "belt and encoder inertia", "bearing drag", "motor cold loss"],
                             applies_to_smooth_constant_acceleration_example_only=True))

unbalance = [dict(assumed_imbalance_mass_g=m, radius_mm=100,
                  radial_force_at_60kmh_N=m / 1000 * R * omega * omega)
             for m in [1, 5, 10]]
contact_latency = [dict(assumed_contact_stiffness_N_mm=k, assumed_touch_speed_mm_s=v,
                        assumed_total_latency_ms=t,
                        estimated_force_rise_during_latency_N=k * v * t / 1000,
                        excludes_inertia_and_deceleration=True)
                   for k in [50, 200, 1000] for v in [0.1, 1, 5] for t in [10, 50, 100]]
friction_energy = [dict(Fx_N=f, tread_speed_kmh=s, duration_s=t,
                        friction_power_W=f * s / 3.6, friction_work_J=f * s / 3.6 * t,
                        heat_to_specimen_fraction=None)
                   for f in [10, 50, 100] for s in [10, 30, 60] for t in [1, 5, 10]]
low_load = []
for n in [25, 50, 100]:
    f = 0.1 * n
    low_load.append(dict(N_N=n, assumed_coefficient=0.1, Fx_N=f,
                         candidate_Fx_single_nonlinearity_scale_N=200 * 0.005,
                         nonlinearity_scale_relative_to_Fx=(200 * 0.005) / f,
                         not_a_complete_uncertainty_budget=True))
newton = dict(reference_moving_mass_kg=previous["baseline_reference"]["moving_ZW_mass_kg"],
              support_force_at_N50_N=previous["baseline_reference"]["moving_ZW_mass_kg"] * G - 50,
              support_force_at_N100_N=previous["baseline_reference"]["moving_ZW_mass_kg"] * G - 100,
              illustrative_fall_distance_mm=10,
              gravitational_energy_for_10mm_fall_J=previous["baseline_reference"]["moving_ZW_mass_kg"] * G * 0.01,
              actual_drop_or_contact_peak_N=None)
whole_snow = [dict(chamber_floor_area_m2=24, illustrative_snow_density_kg_m3=500,
                    snow_thickness_mm=t, snow_mass_kg=24 * t / 1000 * 500,
                    snow_load_kg_m2=t / 1000 * 500, snow_density_is_confirmed_design_factor=False)
              for t in [50, 80]]
parts = list(csv.DictReader((DEVICE / "common_support_v0_31/parts.csv").open(encoding="utf-8-sig")))
packs = {}
for p in parts:
    if p["kind"] == "normal":
        packs[p["pack"]] = packs.get(p["pack"], 0) + float(p["mass_kg"])

result = dict(version="v0.34", date="2026-10-15", purpose="systematic engineering review",
              experiment_goal_confirmed="steady wheel-load friction; acceleration/deceleration establishes/ends operating conditions",
              baseline_CAD="v0.31 old solid125x25", candidate_wheel="v0.33 K909200x50 pneumatic",
              new_pneumatic_CAD_integrated=False, floor=floor,
              yaw_support=dict(model="four equally stiff vertical point supports; constructed X shear distribution",
                               worst=worst_yaw, cases=yaw_cases,
                               actual_each_foot_mu_and_contact_area_unknown=True),
              partial_dynamics=dynamics, unbalance_examples=unbalance,
              contact_latency_examples=contact_latency, friction_energy=friction_energy,
              low_load_measurement_examples=low_load, vertical_force_and_drop=newton,
              whole_floor_snow_load_examples=whole_snow, old_parts_pack_masses_kg=packs,
              known_material_data=dict(motor_rotor_J_reference_kg_m2=Jm,
                                       motor_reference_is_unbraked=True,
                                       SRI_M3725A_operating_C=[-40,100], SRI_M3725A_compensated_C=[10,70]),
              assumptions_are_not_operating_limits=True,
              input_sha256={str(p.relative_to(DEVICE)): hashlib.sha256(p.read_bytes()).hexdigest()
                            for p in [DEVICE / "pneumatic_rebaseline_v0_32/calculation.json",
                                      DEVICE / "pneumatic_wheel_selection_v0_33/wheel_brief.json",
                                      DEVICE / "common_support_v0_31/control_task_contract.json",
                                      DEVICE / "common_support_v0_31/parts.csv",
                                      DEVICE / "component_closure_v0_26/sources/rotation_page.html"]})
(HERE / "system_calculations.json").write_text(json.dumps(result, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
print(json.dumps(dict(floor=floor, worst_yaw=worst_yaw,
                     sample_dynamics=dynamics[3:6], low_load=low_load, vertical=newton), ensure_ascii=False, indent=2))
