"""
Faraday's law (∇×E = −∂B/∂t).

Assertion-based CAS audit block.
Pillar: Electromagnetism | Chain: differential Faraday → Stokes → integral form → localisation
CalRef: Math Appendix §3.4–3.6, EM Calibration §2B
"""


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

    print('=== CAS AUDIT: F0022 — Faraday\'s law ===\n')

    pass_count = 0
    fail_count = 0
    total_steps = 0

    # ---- A. INPUTS ----
    x, y, z, t = symbols('x y z t', real=True)

    # E-field and B-field components as functions
    Ex = Function('Ex')(x, y, z, t)
    Ey = Function('Ey')(x, y, z, t)
    Ez = Function('Ez')(x, y, z, t)
    Bx = Function('Bx')(x, y, z, t)
    By = Function('By')(x, y, z, t)
    Bz = Function('Bz')(x, y, z, t)

    # Curl of E
    curlE_x = diff(Ez, y) - diff(Ey, z)
    curlE_y = diff(Ex, z) - diff(Ez, x)
    curlE_z = diff(Ey, x) - diff(Ex, y)

    # Faraday RHS
    faraday_rhs_x = -diff(Bx, t)
    faraday_rhs_y = -diff(By, t)
    faraday_rhs_z = -diff(Bz, t)

    print('Section D: Step log')
    print('---------------------------------------------')

    # --- Step 1: Curl structure ---
    curlE_x_manual = diff(Ez, y) - diff(Ey, z)
    res1 = simplify(curlE_x - curlE_x_manual)
    total_steps += 1
    if simplify(res1) == 0:
        print('  Step 1  PASS — (∇×E)_x = dEz/dy − dEy/dz')
        pass_count += 1
    else:
        print(f'  Step 1  FAIL')
        fail_count += 1

    curlE_y_manual = diff(Ex, z) - diff(Ez, x)
    res1b = simplify(curlE_y - curlE_y_manual)
    total_steps += 1
    if simplify(res1b) == 0:
        print('  Step 1b PASS — (∇×E)_y = dEx/dz − dEz/dx')
        pass_count += 1
    else:
        print(f'  Step 1b FAIL')
        fail_count += 1

    curlE_z_manual = diff(Ey, x) - diff(Ex, y)
    res1c = simplify(curlE_z - curlE_z_manual)
    total_steps += 1
    if simplify(res1c) == 0:
        print('  Step 1c PASS — (∇×E)_z = dEy/dx − dEx/dy')
        pass_count += 1
    else:
        print(f'  Step 1c FAIL')
        fail_count += 1

    # --- Step 2: Faraday concrete test ---
    f_t = Function('f_t')
    F_t = Function('F_t')

    Ex_c = 0
    Ey_c = -x * f_t(t)
    Ez_c = 0
    Bx_c = 0
    By_c = 0
    Bz_c = F_t(t)

    curlEc_x = diff(Ez_c, y) - diff(Ey_c, z)
    curlEc_y = diff(Ex_c, z) - diff(Ez_c, x)
    curlEc_z = diff(Ey_c, x) - diff(Ex_c, y)

    fara_rhs_cx = -diff(Bx_c, t)
    fara_rhs_cy = -diff(By_c, t)
    fara_rhs_cz = -diff(Bz_c, t)

    res2x = simplify(curlEc_x - fara_rhs_cx)
    total_steps += 1
    if simplify(res2x) == 0:
        print('  Step 2x PASS — Faraday x-component: 0 = 0 (concrete)')
        pass_count += 1
    else:
        print(f'  Step 2x FAIL')
        fail_count += 1

    res2y = simplify(curlEc_y - fara_rhs_cy)
    total_steps += 1
    if simplify(res2y) == 0:
        print('  Step 2y PASS — Faraday y-component: 0 = 0 (concrete)')
        pass_count += 1
    else:
        print(f'  Step 2y FAIL')
        fail_count += 1

    # z-component with F' = f substitution
    res2z_raw = simplify(curlEc_z - fara_rhs_cz)
    res2z = res2z_raw.subs(diff(F_t(t), t), f_t(t))
    total_steps += 1
    if simplify(res2z) == 0:
        print('  Step 2z PASS — Faraday z-component: −f = −F′ with F′=f')
        pass_count += 1
    else:
        print(f'  Step 2z FAIL')
        fail_count += 1

    # --- Step 3: Stokes surface integral ---
    L_s, W_s = symbols('L_s W_s', real=True, positive=True)
    stokes_integrand = -f_t(t)
    stokes_integral = stokes_integrand * L_s * W_s
    stokes_expected = -f_t(t) * L_s * W_s
    res3 = simplify(stokes_integral - stokes_expected)
    total_steps += 1
    if simplify(res3) == 0:
        print('  Step 3  PASS — ∫(∇×E)_z dA = −f(t)·L·W (Stokes)')
        pass_count += 1
    else:
        print(f'  Step 3  FAIL')
        fail_count += 1

    # --- Step 4: Flux and EMF equivalence ---
    Phi_B = F_t(t) * L_s * W_s
    dPhi_dt = diff(Phi_B, t)
    dPhi_dt_sub = dPhi_dt.subs(diff(F_t(t), t), f_t(t))
    emf = -dPhi_dt_sub
    res4 = simplify(stokes_integral - emf)
    total_steps += 1
    if simplify(res4) == 0:
        print('  Step 4  PASS — ∮E·dl = −dΦ_B/dt (Faraday integral form)')
        pass_count += 1
    else:
        print(f'  Step 4  FAIL')
        fail_count += 1

    # --- Step 5: Localisation ---
    loc_integrand_z = curlEc_z + diff(Bz_c, t)
    loc_sub = loc_integrand_z.subs(diff(F_t(t), t), f_t(t))
    res5 = simplify(loc_sub)
    total_steps += 1
    if simplify(res5) == 0:
        print('  Step 5  PASS — Localisation: correct→0, wrong B→−2f≠0')
        pass_count += 1
    else:
        print(f'  Step 5  FAIL')
        fail_count += 1

    # --- Step 6: Numerical — solenoid EMF ---
    N_val = 100
    A_val = 0.01
    dBdt_val = 0.5
    emf_val = -N_val * A_val * dBdt_val
    emf_expected = -0.5
    total_steps += 1
    if abs(emf_val - emf_expected) < 1e-12:
        print(f'  Step 6  PASS — Solenoid: EMF = {emf_val:.2f} V (N={N_val}, A={A_val} m², dB/dt={dBdt_val} T/s)')
        pass_count += 1
    else:
        print(f'  Step 6  FAIL')
        fail_count += 1

    # --- Step 7: Cross-block sign consistency ---
    ratio_sign = simplify(curlEc_z / diff(Bz_c, t))
    ratio_sub = ratio_sign.subs(diff(F_t(t), t), f_t(t))
    res7 = simplify(ratio_sub - (-1))
    total_steps += 1
    if simplify(res7) == 0:
        print('  Step 7  PASS — Sign consistency: (∇×E)/(∂B/∂t) = −1')
        pass_count += 1
    else:
        print(f'  Step 7  FAIL')
        fail_count += 1

    # --- Step 8: Self-test — wrong sign ---
    wrong_rhs_z = diff(Bz_c, t)
    res_wrong = simplify(wrong_rhs_z - fara_rhs_cz)
    res_wrong_sub = res_wrong.subs(diff(F_t(t), t), f_t(t))
    total_steps += 1
    if not (simplify(res_wrong_sub) == 0):
        print('  Step 8a PASS — Wrong sign (+∂B/∂t) detected as incorrect')
        pass_count += 1
    else:
        print(f'  Step 8a FAIL')
        fail_count += 1

    res_wrong_quant = simplify(res_wrong_sub - 2*f_t(t))
    total_steps += 1
    if simplify(res_wrong_quant) == 0:
        print('  Step 8b PASS — Wrong residual = 2f(t) (quantified)')
        pass_count += 1
    else:
        print(f'  Step 8b FAIL')
        fail_count += 1

    print('---------------------------------------------\n')

    # ---- VERDICT ----
    print('=============================================')
    print('  F0022 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(f'  ✓ F0022 — {pass_count}/{total_steps} PASS')


if __name__ == '__main__':
    run()
