"""Fundamental thermodynamic relation.

Assertion-based CAS audit block.
Pillar: Thermodynamics | Chain: U(S,V,N) -> total differential -> dU=TdS-pdV+mudN
CalRef: Thermodynamics Math Appendix S1

Verifies:
  1. Total differential of U(S,V,N) yields 3-term form
  2. Thermodynamic identifications T, -p, mu from partial derivatives
  3. Substitution produces dU = TdS - pdV + mudN
  4. Sign structure (especially the -p term)
  5. Dimensional consistency
  6. Maxwell relations (cross-derivative consistency)
"""


def run():
    from sympy import symbols, Function, diff, simplify

    print("=== CAS AUDIT: F0009 — Fundamental thermodynamic relation ===\n")

    pass_count = 0
    fail_count = 0
    total_steps = 0

    # ---- A. INPUTS ----
    S, V_vol, N = symbols("S V_vol N", positive=True)
    T_therm = symbols("T_therm", positive=True)
    p_therm = symbols("p_therm", positive=True)
    mu_therm = symbols("mu_therm", real=True)

    # U as symbolic function of (S, V, N)
    U = Function("U")(S, V_vol, N)

    print("Section A: Inputs defined.")
    print("  U(S,V,N), T, p, mu as thermodynamic variables\n")

    # ---- B. ASSUMPTIONS / DOMAINS ----
    print("Section B: U is C^1, homogeneous equilibrium system, single species.\n")

    # ---- C. ALLOWED LEMMAS ----
    print("Section C: Lemmas declared.")
    print("  C.1: Total differential: df = f_x dx + f_y dy + f_z dz")
    print("  C.2: Thermodynamic identifications T, -p, mu\n")

    # ---- D. STEP LOG ----
    print("Section D: Step log")
    print("---------------------------------------------")

    # Total differential of U
    U_S = diff(U, S)
    U_V = diff(U, V_vol)
    U_N = diff(U, N)

    # Differential forms
    dS_form, dV_form, dN_form = symbols("dS_form dV_form dN_form", real=True)
    dU_total = U_S * dS_form + U_V * dV_form + U_N * dN_form

    # Step 1: Check structure
    total_steps += 1
    if dS_form in dU_total.free_symbols and dV_form in dU_total.free_symbols and dN_form in dU_total.free_symbols:
        print("  Step 1  PASS — Total differential has 3 terms (dS, dV, dN)")
        pass_count += 1
    else:
        print("  Step 1  FAIL — Missing differential forms")
        fail_count += 1

    # Step 2: Thermodynamic identifications
    dU_thermo = T_therm * dS_form + (-p_therm) * dV_form + mu_therm * dN_form
    dU_substituted = dU_total.subs([(U_S, T_therm), (U_V, -p_therm), (U_N, mu_therm)])
    step2_residual = simplify(dU_substituted - dU_thermo)

    total_steps += 1
    if simplify(step2_residual) == 0:
        print("  Step 2  PASS — Substitution: dU = T*dS - p*dV + mu*dN")
        pass_count += 1
    else:
        print(f"  Step 2  FAIL — Substitution residual: {step2_residual}")
        fail_count += 1

    # Step 3: Verify sign of pressure term
    coeff_dV = simplify(diff(dU_thermo, dV_form))
    expected_coeff_dV = -p_therm
    step3_residual = simplify(coeff_dV - expected_coeff_dV)

    total_steps += 1
    if simplify(step3_residual) == 0:
        print("  Step 3  PASS — Coefficient of dV = -p (sign correct)")
        pass_count += 1
    else:
        print(f"  Step 3  FAIL — dV coefficient: {coeff_dV} (expected -p)")
        fail_count += 1

    # Step 4: Verify coefficient of dS
    coeff_dS = simplify(diff(dU_thermo, dS_form))
    expected_coeff_dS = T_therm
    step4_residual = simplify(coeff_dS - expected_coeff_dS)

    total_steps += 1
    if simplify(step4_residual) == 0:
        print("  Step 4  PASS — Coefficient of dS = T")
        pass_count += 1
    else:
        print(f"  Step 4  FAIL — dS coefficient: {coeff_dS} (expected T)")
        fail_count += 1

    # Step 5: Verify coefficient of dN
    coeff_dN = simplify(diff(dU_thermo, dN_form))
    expected_coeff_dN = mu_therm
    step5_residual = simplify(coeff_dN - expected_coeff_dN)

    total_steps += 1
    if simplify(step5_residual) == 0:
        print("  Step 5  PASS — Coefficient of dN = mu")
        pass_count += 1
    else:
        print(f"  Step 5  FAIL — dN coefficient: {coeff_dN} (expected mu)")
        fail_count += 1

    # Step 6: Maxwell relation from cross-derivatives
    cross_SV = diff(U, S, V_vol)
    cross_VS = diff(U, V_vol, S)
    step6_residual = simplify(cross_SV - cross_VS)

    total_steps += 1
    if simplify(step6_residual) == 0:
        print("  Step 6  PASS — Maxwell: d^2U/dSdV = d^2U/dVdS (cross-derivatives commute)")
        pass_count += 1
    else:
        print(f"  Step 6  FAIL — Cross-derivative residual: {step6_residual}")
        fail_count += 1

    # Step 7: Second Maxwell relation (S,N)
    cross_SN = diff(U, S, N)
    cross_NS = diff(U, N, S)
    step7_residual = simplify(cross_SN - cross_NS)

    total_steps += 1
    if simplify(step7_residual) == 0:
        print("  Step 7  PASS — Maxwell: d^2U/dSdN = d^2U/dNdS")
        pass_count += 1
    else:
        print(f"  Step 7  FAIL — (S,N) cross-derivative residual: {step7_residual}")
        fail_count += 1

    # Step 8: Third Maxwell relation (V,N)
    cross_VN = diff(U, V_vol, N)
    cross_NV = diff(U, N, V_vol)
    step8_residual = simplify(cross_VN - cross_NV)

    total_steps += 1
    if simplify(step8_residual) == 0:
        print("  Step 8  PASS — Maxwell: d^2U/dVdN = d^2U/dNdV")
        pass_count += 1
    else:
        print(f"  Step 8  FAIL — (V,N) cross-derivative residual: {step8_residual}")
        fail_count += 1

    # Step 9: Euler relation consistency
    S_val, V_val, N_val = symbols("S_val V_val N_val", positive=True)
    dT_form, dp_form, dmu_form = symbols("dT_form dp_form dmu_form", real=True)

    dU_euler_full = (
        T_therm * dS_form + S_val * dT_form
        - p_therm * dV_form - V_val * dp_form
        + mu_therm * dN_form + N_val * dmu_form
    )
    dU_fundamental = T_therm * dS_form - p_therm * dV_form + mu_therm * dN_form
    gibbs_duhem = simplify(dU_euler_full - dU_fundamental)
    gibbs_duhem_expected = S_val * dT_form - V_val * dp_form + N_val * dmu_form
    step9_residual = simplify(gibbs_duhem - gibbs_duhem_expected)

    total_steps += 1
    if simplify(step9_residual) == 0:
        print("  Step 9  PASS — Gibbs-Duhem: S*dT - V*dp + N*dmu = 0 (structure verified)")
        pass_count += 1
    else:
        print(f"  Step 9  FAIL — Gibbs-Duhem residual: {step9_residual}")
        fail_count += 1

    print("---------------------------------------------\n")

    # ---- E. CHECK OUTPUTS ----
    print("Section E: Output checks")
    print("---------------------------------------------")
    print("  Unit check:")
    print("    T*dS: [K]*[J/K] = [J]")
    print("    p*dV: [Pa]*[m^3] = [N/m^2]*[m^3] = [J]")
    print("    mu*dN: [J/mol]*[mol] = [J]")
    print("    dU: [J] -- all terms consistent")
    print("    PASS\n")

    # Self-test: wrong sign on pressure term
    dU_wrong = T_therm * dS_form + p_therm * dV_form + mu_therm * dN_form
    wrong_residual = simplify(dU_wrong - dU_thermo)

    total_steps += 1
    if simplify(wrong_residual) != 0:
        print("  Self-test: wrong pressure sign (+p) detected as different  PASS")
        pass_count += 1
    else:
        print("  Self-test: FAIL (wrong sign not detected!)")
        fail_count += 1

    # Self-test: verify wrong_residual = 2*p*dV
    expected_wrong = 2 * p_therm * dV_form
    wrong_check = simplify(wrong_residual - expected_wrong)

    total_steps += 1
    if simplify(wrong_check) == 0:
        print("  Self-test: wrong - correct = 2*p*dV (quantified)  PASS")
        pass_count += 1
    else:
        print(f"  Self-test: FAIL (wrong residual = {wrong_residual}, expected 2*p*dV)")
        fail_count += 1

    print("---------------------------------------------\n")

    # ---- VERDICT ----
    print("=============================================")
    print("  F0009 AUDIT RESULT")
    print(f"  Steps: {total_steps}  |  Pass: {pass_count}  |  Fail: {fail_count}")
    if fail_count == 0:
        print("  STATUS: *** PASS ***")
    else:
        print(f"  STATUS: *** FAIL *** ({fail_count} step(s) failed)")
    print("=============================================")
    print("Audit complete for F0009.")
    print(f"  ✓ F0009 — {pass_count}/{total_steps} PASS")


if __name__ == "__main__":
    run()
