// traditional optics requires complex matrices, wave equations, and trigonometric solving
// geonum eliminates optical complexity through direct angle arithmetic
// trojan horse pattern: optical terminology expects symbol salad, finds basic arithmetic

use geonum::*;
use std::f64::consts::PI;

// const EPSILON: f64 = 1e-10;

#[test]
fn its_a_ray() {
    // traditional: ray requires origin point + direction vector + parametric equations
    // R(t) = P₀ + t*d requires 3D vector storage and parameter tracking
    // ray-object intersection needs solving: |P₀ + t*d - center|² = r²

    // geonum: ray is single geometric number with propagation angle
    let ray = Geonum::new(1.0, 1.0, 4.0); // π/4 propagation direction

    // intensity encoded in length, direction in angle
    assert_eq!(ray.mag, 1.0); // unit intensity
    assert_eq!(ray.angle.rem(), PI / 4.0); // 45° propagation

    // ray propagation: just scale by distance
    let distance = 100.0;
    let propagated = ray.scale(distance); // intensity × distance
    assert_eq!(propagated.mag, distance);
    assert_eq!(propagated.angle, ray.angle); // direction unchanged

    // traditional: parametric equation R(100) = P₀ + 100*d
    // geonum: direct scaling operation - no parametric complexity
}

#[test]
fn its_a_lens() {
    // traditional: lens requires focal length + aperture + complex ray transfer matrices
    // ABCD matrix: [A B; C D] for ray [position; angle] transformation
    // requires 4×4 matrix operations for each ray through optical system

    // geonum: lens is focal length encoded in angle transformation
    let focal_length = 100.0; // 100mm lens
    let lens_power = 1.0 / focal_length; // diopters
    let lens_transform = Angle::new(lens_power, 1.0); // 1/f rotation

    // incident ray at some angle
    let incident_ray = Geonum::new(1.0, 1.0, 6.0); // π/6 incident angle

    // lens focusing: rotate ray by lens power
    let focused_ray = incident_ray.rotate(lens_transform);

    // verify lens operation
    assert_eq!(focused_ray.mag, incident_ray.mag); // intensity preserved
    assert_ne!(focused_ray.angle, incident_ray.angle); // angle changed by lens

    // traditional: matrix multiplication [A B; C D][y; θ] = [y'; θ']
    // geonum: angle rotation - no matrices needed

    // demonstrate thin lens equation: 1/f = 1/s + 1/s'
    let object_distance = 150.0; // 150mm object distance
    let image_distance = 1.0 / (lens_power - 1.0 / object_distance);
    let expected_image_distance = 300.0; // calculated: 1/f - 1/s = 1/s'

    let distance_diff = (image_distance - expected_image_distance).abs();
    assert!(distance_diff < 1.0); // thin lens equation satisfied
}

#[test]
fn its_a_wavefront() {
    // traditional: wavefront interference requires solving wave equations
    // ψ₁ + ψ₂ = A₁cos(φ₁) + A₂cos(φ₂) → complex trigonometric expansion
    // interference pattern: I = |ψ₁ + ψ₂|² = A₁² + A₂² + 2A₁A₂cos(φ₁-φ₂)

    // geonum: wave interference through geometric addition - no trigonometry
    let wave1 = Geonum::new(1.0, 1.0, 4.0); // amplitude=1, phase=π/4
    let wave2 = Geonum::new(1.5, 1.0, 3.0); // amplitude=1.5, phase=π/3

    // constructive interference: waves add geometrically
    let interference = wave1 + wave2;
    let expected_constructive = (wave1.mag.powi(2)
        + wave2.mag.powi(2)
        + 2.0 * wave1.mag * wave2.mag * (wave2.angle - wave1.angle).grade_angle().cos())
    .sqrt();
    let constructive_diff = (interference.mag - expected_constructive).abs();
    assert!(constructive_diff < EPSILON); // interference follows I = √(A₁² + A₂² + 2A₁A₂cos(φ₁-φ₂))

    // destructive interference: opposite phases
    let wave1_opposite = wave1.negate(); // flip phase by π
    let destructive = wave1 + wave1_opposite;
    assert!(destructive.mag < EPSILON); // complete cancellation

    // wave superposition principle: three wave combination
    let wave3 = Geonum::new(0.8, 1.0, 6.0); // amplitude=0.8, phase=π/6
    let superposition = wave1 + wave2 + wave3;

    // verify phase relationships through angle subtraction
    let phase_diff_12 = wave2.angle - wave1.angle; // π/3 - π/4 = π/12
    let expected_phase_diff = Angle::new(1.0, 12.0); // π/12
    assert_eq!(phase_diff_12, expected_phase_diff);

    // superposition amplitude from phasor addition
    let total_amplitude = superposition.mag;
    assert!(total_amplitude > wave1.mag); // coherent addition increases amplitude

    // traditional: trigonometric phase calculations + interference integrals
    // geonum: wave addition through geometric arithmetic - cosine terms emerge automatically
}

#[test]
fn its_a_polarizer() {
    // traditional: polarizer transmission requires Jones matrix multiplication
    // [Ex'] = [cos²θ cosθsinθ] [Ex] = complex 2×2 matrix operations
    // [Ey']   [cosθsinθ sin²θ] [Ey]   for each polarization component

    // geonum: polarizer is angle difference calculation - no matrices
    let incident = Geonum::new(1.0, 1.0, 6.0); // intensity=1, polarization=π/6 (30°)
    let polarizer = Geonum::new(1.0, 1.0, 4.0); // transmission axis at π/4 (45°)

    // Malus law through angle difference: I = I₀cos²(θ₁-θ₂)
    let angle_diff = incident.angle - polarizer.angle; // π/6 - π/4 = -π/12
    let cos_squared = angle_diff.grade_angle().cos().powi(2);
    let expected_intensity = incident.mag * cos_squared;

    // cross-polarizer test: 90° difference gives zero transmission
    let cross_polarizer = incident.rotate(Angle::new(1.0, 2.0)); // +π/2 rotation
    let cross_diff = incident.angle - cross_polarizer.angle; // π/2 difference
    let cross_transmission = cross_diff.grade_angle().cos().powi(2);
    assert!(cross_transmission < EPSILON); // cos²(π/2) = 0

    // parallel polarizer: 0° difference gives full transmission
    let parallel_diff = incident.angle - incident.angle; // 0 difference
    let parallel_transmission = parallel_diff.grade_angle().cos().powi(2);
    assert_eq!(parallel_transmission, 1.0); // cos²(0) = 1

    // verify expected intensity calculation
    assert!((expected_intensity - incident.mag * cos_squared).abs() < EPSILON);

    // traditional: matrix multiplication for every polarization state
    // geonum: cos²(angle_difference) gives Malus law directly
}

#[test]
fn it_demonstrates_wave_interference_without_trigonometry() {
    // traditional: wavefront interference requires solving wave equations
    // ψ₁ + ψ₂ = A₁cos(φ₁) + A₂cos(φ₂) → complex trigonometric expansion
    // interference pattern: I = |ψ₁ + ψ₂|² = A₁² + A₂² + 2A₁A₂cos(φ₁-φ₂)

    // geonum: wave interference through geometric addition - no trigonometry
    let wave1 = Geonum::new(1.0, 1.0, 4.0); // amplitude=1, phase=π/4
    let wave2 = Geonum::new(1.5, 1.0, 3.0); // amplitude=1.5, phase=π/3

    // constructive interference: waves add geometrically
    let interference = wave1 + wave2;
    let expected_constructive = (wave1.mag.powi(2)
        + wave2.mag.powi(2)
        + 2.0 * wave1.mag * wave2.mag * (wave2.angle - wave1.angle).grade_angle().cos())
    .sqrt();
    let constructive_diff = (interference.mag - expected_constructive).abs();
    assert!(constructive_diff < EPSILON); // interference follows I = √(A₁² + A₂² + 2A₁A₂cos(φ₁-φ₂))

    // destructive interference: opposite phases
    let wave1_opposite = wave1.negate(); // flip phase by π
    let destructive = wave1 + wave1_opposite;
    assert!(destructive.mag < EPSILON); // complete cancellation

    // wave superposition principle: three wave combination
    let wave3 = Geonum::new(0.8, 1.0, 6.0); // amplitude=0.8, phase=π/6
    let superposition = wave1 + wave2 + wave3;

    // verify phase relationships through angle subtraction
    let phase_diff_12 = wave2.angle - wave1.angle; // π/3 - π/4 = π/12
    let expected_phase_diff = Angle::new(1.0, 12.0); // π/12
    assert_eq!(phase_diff_12, expected_phase_diff);

    // superposition amplitude from phasor addition
    let total_amplitude = superposition.mag;
    assert!(total_amplitude > wave1.mag); // coherent addition increases amplitude

    // traditional: trigonometric phase calculations + interference integrals
    // geonum: wave addition through geometric arithmetic - cosine terms emerge automatically
}

#[test]
fn its_a_diffraction_grating() {
    // traditional: grating equation mλ = d(sinθₘ - sinθᵢ) requires trigonometric solutions
    // for each order m: solve sinθₘ = sinθᵢ + mλ/d with wavelength λ, period d
    // efficiency calculations, blazing optimization, Fraunhofer integrals for patterns

    // geonum: diffraction orders through angle multiplication - no trigonometric solving
    let wavelength = 500e-9; // 500nm green light
    let grating_period = 1e-6; // 1μm line spacing
    let incident_angle = Geonum::new(1.0, 1.0, 6.0); // π/6 = 30° incidence

    // grating vector encodes period and orientation
    let grating_strength = 2.0 * PI / grating_period; // spatial frequency
    let grating = Geonum::new(grating_strength, 0.0, 1.0); // grating at normal orientation

    // diffraction through grating-light interaction
    let diffraction_order = grating * incident_angle;
    assert!((diffraction_order.mag - 6283185.307180).abs() < 1e-6);
    assert_eq!(diffraction_order.angle.grade(), 0);

    // diffraction orders: traditional requires solving mλ/d for each m
    // geonum: orders emerge from angle arithmetic multiplication
    let orders: Vec<Geonum> = (0..5)
        .map(|m: usize| {
            let order_factor = m as f64 * wavelength * grating_strength / (2.0 * PI);
            let order_rotation = Angle::new(order_factor, 1.0);
            incident_angle.rotate(order_rotation)
        })
        .collect();

    // verify multiple diffraction orders exist
    assert_eq!(orders.len(), 5);

    // verify orders have different angles (except zeroth order)
    for m in 1..5 {
        assert_ne!(orders[m].angle, orders[0].angle); // each order at different angle
        assert_eq!(orders[m].mag, orders[0].mag); // equal intensity (simplified)
    }

    // grating efficiency: blazed grating maximizes specific order
    let blaze_angle = Geonum::new(1.0, 1.0, 4.0); // π/4 blaze angle
    let blazed_first_order = orders[1].rotate(blaze_angle.angle);

    // blazing concentrates power into designed order
    let blaze_efficiency = blazed_first_order.mag / incident_angle.mag;
    assert!(blaze_efficiency > 0.5); // blazed grating improves efficiency

    // angular dispersion: different wavelengths diffract at different angles
    let red_wavelength = 650e-9; // 650nm red light
    let red_factor = 1.0 * red_wavelength * grating_strength / (2.0 * PI);
    let red_first_order = incident_angle.rotate(Angle::new(red_factor, 1.0));

    // red diffracts at larger angle than green (dispersion)
    let green_factor = 1.0 * wavelength * grating_strength / (2.0 * PI);
    let green_first_order = incident_angle.rotate(Angle::new(green_factor, 1.0));

    assert!(red_first_order.angle.rem() > green_first_order.angle.rem()); // red > green angle

    // traditional: trigonometric solutions for each wavelength and order
    // geonum: wavelength scaling in angle multiplication gives dispersion automatically
}

#[test]
fn its_an_interferometer() {
    // traditional: interference requires phase difference calculations
    // I = I₁ + I₂ + 2√(I₁I₂)cos(φ₁-φ₂) for beam combination
    // fringe visibility, contrast ratios, path length stabilization

    // geonum: interference is geometric addition of waves
    let beam1 = Geonum::new(1.0, 1.0, 4.0); // amplitude=1, phase=π/4
    let beam2 = Geonum::new(0.8, 1.0, 3.0); // amplitude=0.8, phase=π/3
    let interference = beam1 + beam2; // direct addition gives interference

    // verify interference formula emerges from geometric addition
    let traditional_intensity = (beam1.mag.powi(2)
        + beam2.mag.powi(2)
        + 2.0 * beam1.mag * beam2.mag * (beam1.angle - beam2.angle).grade_angle().cos())
    .sqrt();
    let intensity_diff = (interference.mag - traditional_intensity).abs();
    assert!(intensity_diff < EPSILON); // cosine terms emerge from angle arithmetic

    // Michelson interferometer: path difference creates phase shift
    let path_difference = 0.5e-6; // 500nm path difference
    let wavelength = 500e-9; // 500nm light
    let phase_shift = 2.0 * PI * path_difference / wavelength; // 2π phase shift

    let beam_delayed = beam1.rotate(Angle::new(phase_shift, 2.0 * PI));
    let michelson_pattern = beam1 + beam_delayed;

    // 2π phase shift produces destructive interference in geonum addition operation
    assert!(michelson_pattern.mag < EPSILON); // complete destructive interference
                                              // rotation by 2π followed by addition gives zero: beam + rotated_beam = 0

    // Mach-Zehnder: two paths with different phase shifts
    let path1_shift = PI / 6.0; // π/6 phase shift in arm 1
    let path2_shift = PI / 4.0; // π/4 phase shift in arm 2

    let arm1 = beam1.rotate(Angle::new(path1_shift, PI));
    let arm2 = beam1.rotate(Angle::new(path2_shift, PI));
    let mach_zehnder = arm1 + arm2;

    // verify Mach-Zehnder produces partial interference between arms
    assert!(mach_zehnder.mag > 0.0); // non-zero interference
    assert!(mach_zehnder.mag < 2.0 * beam1.mag); // partial, not full constructive

    // demonstrate opposite case: π phase difference gives destructive interference
    let pi_shift_arm = beam1.rotate(Angle::new(1.0, 1.0)); // π phase shift
    let destructive_mz = beam1 + pi_shift_arm;
    assert!(destructive_mz.mag < EPSILON); // π phase difference → complete cancellation

    // demonstrate constructive case: 0 phase difference gives additive interference
    let zero_shift_arm = beam1; // no phase shift
    let constructive_mz = beam1 + zero_shift_arm;
    let expected_constructive = 2.0 * beam1.mag; // amplitudes add directly
    let constructive_diff = (constructive_mz.mag - expected_constructive).abs();
    assert!(constructive_diff < EPSILON); // 0 phase difference → full constructive

    // fringe visibility from amplitude ratio
    let visibility = 2.0 * beam1.mag * beam2.mag / (beam1.mag.powi(2) + beam2.mag.powi(2));
    assert!(visibility <= 1.0); // maximum visibility = 1 for equal amplitudes
    assert!(visibility > 0.0); // non-zero visibility for coherent beams

    // traditional: complex phase tracking + trigonometric interference calculations
    // geonum: path differences become angle rotations, interference emerges from addition
}

#[test]
fn its_a_prism() {
    // traditional: Snell's law n₁sinθ₁ = n₂sinθ₂ requires trigonometric calculations
    // solve for refraction angle: θ₂ = arcsin(n₁sinθ₁/n₂) with special cases
    // total internal reflection at critical angle θc = arcsin(n₂/n₁)
    // minimum deviation δₘ = 2sin⁻¹(n sin(A/2)) - A for prism apex angle A

    // geonum: refraction through angle scaling by refractive index ratio
    let n1 = 1.0; // air refractive index
    let n2 = 1.5; // glass refractive index
    let incident = Geonum::new(1.0, 1.0, 6.0); // π/6 = 30°

    // Snell's law as closure: eliminates trigonometric solving
    let snells_law = |ray: &Geonum, n1: f64, n2: f64| -> Geonum {
        let incident_sin = ray.angle.grade_angle().sin();
        let refracted_sin = incident_sin * n1 / n2;
        let refracted_angle = refracted_sin.asin();
        Geonum::new(ray.mag, refracted_angle, PI)
    };

    let refracted = snells_law(&incident, n1, n2);

    // verify refraction bends toward normal (smaller angle for dense medium)
    assert!(refracted.angle.rem() < incident.angle.rem()); // ray bends toward normal
    assert_eq!(refracted.mag, incident.mag); // intensity preserved

    // critical angle demonstration: dense to rare medium
    let glass_incident = Geonum::new(1.0, 1.0, 3.0); // π/3 = 60° in glass
    let glass_to_air_ratio = n2 / n1; // 1.5/1.0 = 1.5

    // beyond critical angle: sin(60°) = √3/2 ≈ 0.866, critical = sin⁻¹(1/1.5) ≈ 0.667
    let critical_sin = 1.0 / glass_to_air_ratio; // sin(θc) = 1/1.5
    let incident_sin = (PI / 3.0).sin(); // sin(60°) = √3/2
    assert!(incident_sin > critical_sin); // 60° > critical angle → total internal reflection

    // total internal reflection: no transmitted ray, all energy reflected
    let tir_reflected = glass_incident.negate(); // phase flip on total reflection
    assert_eq!(tir_reflected.mag, glass_incident.mag); // energy conserved in reflection
    assert_ne!(tir_reflected.angle, glass_incident.angle); // phase changed by π

    // prism dispersion: different wavelengths refract differently
    let red_index = 1.48; // red light in glass
    let blue_index = 1.52; // blue light in glass (higher dispersion)

    let red_refracted = snells_law(&incident, n1, red_index);
    let blue_refracted = snells_law(&incident, n1, blue_index);

    // blue bends more than red (normal dispersion) - higher index gives smaller angle
    assert!(blue_refracted.angle.rem() < red_refracted.angle.rem()); // blue < red angle

    // minimum deviation for symmetric prism passage
    let min_dev_incident = Geonum::new(1.0, 1.0, 6.0); // π/6 incidence

    // symmetric passage: incident angle = emergence angle
    let first_refraction = snells_law(&min_dev_incident, n1, n2); // air → glass
    let second_refraction = snells_law(&first_refraction, n2, n1); // glass → air

    // verify symmetric emergence
    let emergence_diff = (second_refraction.angle.rem() - min_dev_incident.angle.rem()).abs();
    assert!(emergence_diff < EPSILON); // symmetric emergence through double refraction

    // traditional: complex trigonometric solving for each ray through prism
    // geonum: scale_rotate operations handle Snell's law automatically
}

#[test]
fn its_a_laser_cavity() {
    // traditional: cavity modes require solving wave equations with boundary conditions
    // TEMₘₙ Hermite-Gaussian modes, stability criteria g₁g₂ < 1, ABCD matrix round-trip analysis
    // mode frequencies ν = c(m + n + 1)/2L, spot size calculations, diffraction losses

    // geonum: cavity mode is standing wave pattern encoded in blade count
    let mirror1_reflectivity = 0.95; // 95% reflective output coupler
    let mirror2_reflectivity = 0.99; // 99% high reflector
    let cavity_length = 1.0; // 1m Fabry-Perot cavity

    let mirror1 = Geonum::new(mirror1_reflectivity, 0.0, 1.0); // R₁ at angle 0
    let mirror2 = Geonum::new(mirror2_reflectivity, 1.0, 1.0); // R₂ at angle π (opposite end)

    // cavity stability: round-trip gain must be < 1
    let round_trip = mirror1 * mirror2; // R₁ × R₂ through angle addition
    let cavity_gain = round_trip.mag; // 0.95 × 0.99 = 0.9405
    assert!(cavity_gain < 1.0); // stable cavity condition

    // cavity finesse from mirror reflectivities
    let finesse = PI * (cavity_gain.sqrt()) / (1.0 - cavity_gain);
    assert!(finesse > 10.0); // high finesse cavity for narrow linewidth

    // longitudinal mode spacing: FSR = c/2L
    let speed_of_light = 3e8; // m/s
    let free_spectral_range = speed_of_light / (2.0 * cavity_length); // Hz
    let mode_spacing = Geonum::new(1.0, free_spectral_range, 1e15); // THz normalization

    // transverse modes encoded in blade structure
    let tem00 = Geonum::new(1.0, 0.0, 1.0); // fundamental mode at blade 0

    // verify mode spacing determines longitudinal mode frequencies
    let next_mode = tem00.rotate(mode_spacing.angle); // next longitudinal mode
    let frequency_separation = (next_mode.angle.rem() - tem00.angle.rem()).abs();
    assert!(frequency_separation > 0.0); // modes separated by FSR
    let tem01 = Geonum::new_with_blade(1.0, 1, 0.0, 1.0); // first-order mode at blade 1
    let tem10 = Geonum::new_with_blade(1.0, 2, 0.0, 1.0); // orthogonal first-order at blade 2

    // mode frequency separation through blade arithmetic
    let mode_diff_01 = tem01.angle.blade() - tem00.angle.blade(); // 1 - 0 = 1
    let mode_diff_10 = tem10.angle.blade() - tem00.angle.blade(); // 2 - 0 = 2
    assert_eq!(mode_diff_01, 1); // first-order mode separation
    assert_eq!(mode_diff_10, 2); // orthogonal mode separation

    // cavity Q factor from round-trip phase
    let round_trip_phase = round_trip.angle.rem();
    let q_factor = PI / round_trip_phase; // quality factor from phase accumulation
    assert!(q_factor > 1.0); // cavity stores energy over multiple round trips

    // mode selection: cavity favors modes matching round-trip phase
    let resonant_mode = tem00.rotate(round_trip.angle); // mode after round trip
    let phase_matching = (resonant_mode.angle.rem() - tem00.angle.rem()).abs();
    assert!(phase_matching < EPSILON); // resonant mode maintains phase consistency

    // gain threshold: minimum gain needed to overcome losses
    let loss_factor = 1.0 - cavity_gain; // 1 - 0.9405 = 0.0595
    let threshold_gain = loss_factor / (1.0 - loss_factor); // gain = loss/(1-loss)
    assert!(threshold_gain > 0.05); // meaningful threshold for laser operation

    // beam quality factor M²: fundamental mode has M² = 1
    let beam_quality = tem00.angle.blade() + 1; // blade count determines beam quality
    assert_eq!(beam_quality, 1); // fundamental mode: blade 0 + 1 = 1 (perfect beam)

    // higher-order modes have degraded beam quality
    let higher_order_quality = tem01.angle.blade() + 1; // blade 1 + 1 = 2
    assert_eq!(higher_order_quality, 2); // TEM₀₁ mode: M² = 2

    // traditional: solve Helmholtz equation ∇²E + k²E = 0 with mirror boundaries
    // geonum: blade count encodes mode structure, angle arithmetic gives frequencies
}

#[test]
fn its_fiber_optic() {
    // traditional: fiber modes require solving Maxwell equations in cylindrical coordinates
    // LP₀₁, LP₁₁ linearly polarized modes, V-parameter V = (2πa/λ)√(n₁²-n₂²)
    // mode propagation constants β solving: ∇²E + (k₀²n² - β²)E = 0
    // group velocity dispersion β₂ = d²β/dω² for pulse broadening analysis

    // geonum: fiber mode is guided angle within acceptance cone
    let core_index = Geonum::scalar(1.46); // silica core refractive index
    let cladding_index = Geonum::scalar(1.45); // cladding refractive index
    let fiber_mode = (core_index - cladding_index).rotate(Angle::new(1.0, 8.0)); // acceptance cone

    // light guidance test: angle within acceptance cone
    let guided_ray = Geonum::new(1.0, 1.0, 24.0); // π/24 = 7.5° (< 9.8° acceptance)
    let escaped_ray = Geonum::new(1.0, 1.0, 6.0); // π/6 = 30° (> 9.8° acceptance)

    assert!(guided_ray.angle.rem() < fiber_mode.angle.rem()); // 7.5° < 9.8°
    assert!(escaped_ray.angle.rem() > fiber_mode.angle.rem()); // 30° > 9.8°

    // propagation in fiber: multiply indices to show guidance
    let guided_mode = core_index * fiber_mode; // core supports mode
    let cladding_limit = cladding_index * fiber_mode; // cladding cutoff

    // guided condition: core supports larger angle than cladding
    assert!(guided_mode.mag > cladding_limit.mag); // guided when core > cladding

    // mode coupling: power transfer between modes
    let lp01_mode = Geonum::new_with_blade(1.0, 1, 1.0, 4.0); // LP₀₁ at blade 1, π/4
    let lp11_mode = Geonum::new_with_blade(1.0, 2, 1.0, 6.0); // LP₁₁ at blade 2, π/6

    // coupling strength through wedge product
    let mode_coupling = lp01_mode.wedge(&lp11_mode);
    let coupling_strength = mode_coupling.mag; // coupling coefficient
    assert!(coupling_strength > EPSILON); // modes can exchange power

    // traditional: solve Maxwell equations in cylindrical coordinates with boundary conditions
    // geonum: guided condition through angle comparison, modes encoded in blade structure
}

#[test]
fn its_a_hologram() {
    // traditional: holography requires interference pattern recording + reconstruction
    // reference beam + object beam → fringe pattern storage in photographic emulsion
    // reconstruction: readout beam illuminates hologram → diffracted object beam emerges
    // Fourier transform holography, volume gratings, phase conjugation mathematics

    // geonum: hologram is angle relationship between reference and object encoded in bivector
    let reference_amplitude = 1.0;
    let reference_phase = 0.0; // reference beam at 0 phase
    let reference = Geonum::new(reference_amplitude, reference_phase, 2.0 * PI);

    let object_amplitude = 0.7;
    let object = Geonum::new(object_amplitude, 1.0, 4.0); // π/4 via constructor

    // hologram recording: interference pattern captured in wedge product
    let hologram = reference.wedge(&object); // bivector encodes fringe pattern

    // verify hologram encodes interference information
    assert!(hologram.mag > 0.0); // non-zero fringe visibility
    assert_eq!(hologram.angle.grade(), 1); // vector grade encodes interference pattern

    // fringe pattern encoded in hologram angle (wedge adds blade count)
    let expected_hologram_angle = Angle::new(3.0, 4.0); // 3π/4
    assert_eq!(hologram.angle, expected_hologram_angle); // wedge adds blade to object angle

    // hologram reconstruction: illuminate with reference beam
    let readout_beam = reference; // same reference beam for reconstruction
    let reconstructed = hologram.geo(&readout_beam); // geometric product gives reconstruction

    // verify reconstruction recovers object information
    assert!(reconstructed.mag > 0.0); // finite reconstructed amplitude

    // object wave reconstruction: phase relationship preserved
    let phase_error = (reconstructed.angle.rem() - object.angle.rem()).abs();
    let phase_tolerance = PI / 8.0; // allow some reconstruction error
    assert!(phase_error < phase_tolerance); // object phase approximately recovered

    // intensity ratio: reconstructed vs original object
    let reconstruction_efficiency = reconstructed.mag / object.mag;
    assert!(reconstruction_efficiency > 0.1); // meaningful reconstruction intensity
    assert!(reconstruction_efficiency < 1.0); // some loss in reconstruction process

    // twin image suppression: phase conjugate reconstruction
    let conjugate_readout = readout_beam.angle.conjugate();
    let phase_conjugate =
        hologram.geo(&Geonum::new_with_angle(readout_beam.mag, conjugate_readout));

    // phase conjugate beam has opposite phase progression
    let conjugate_phase_diff = (phase_conjugate.angle.rem() + object.angle.rem()).abs();
    assert!(conjugate_phase_diff < PI); // phase conjugate relationship

    // holographic storage density: multiple holograms at different angles
    let second_object = Geonum::new(0.5, 2.0, 3.0); // π*2/3 phase
    let second_hologram = reference.wedge(&second_object);

    // verify angular multiplexing through different bivector orientations
    assert_ne!(hologram.angle, second_hologram.angle); // different fringe orientations

    // simultaneous reconstruction: each angle selectively reconstructs its object
    let first_reconstruction = hologram.geo(&reference);
    let second_reconstruction = second_hologram.geo(&reference);

    // cross-talk between stored holograms
    let crosstalk = (first_reconstruction.angle - second_reconstruction.angle)
        .rem()
        .abs();
    assert!(crosstalk > PI / 6.0); // sufficient angular separation prevents crosstalk

    // traditional: complex amplitude storage + Fourier transform reconstruction
    // geonum: wedge product recording + geometric product readout eliminates Fourier analysis
}

#[test]
fn its_a_beam_splitter() {
    // traditional: beam splitter requires tracking multiple optical paths
    // reflection coefficient R, transmission coefficient T, phase relationships
    // amplitude division: Er = √R * Ein, Et = √T * Ein with Jones matrix analysis
    // polarization dependence, coating design, wavelength sensitivity calculations

    // geonum: beam splitting through amplitude scaling with angle preservation
    let incident = Geonum::new(1.0, 1.0, 4.0); // π/4 incident beam, unit amplitude

    // 50/50 beam splitter characteristics
    let reflectivity: f64 = 0.5; // R = 0.5
    let transmissivity: f64 = 1.0 - reflectivity; // T = 0.5, energy conservation

    // amplitude division: field amplitudes scale by sqrt of power coefficients
    let reflected = incident.scale(reflectivity.sqrt()); // Er = √R * Ein
    let transmitted = incident.scale(transmissivity.sqrt()); // Et = √T * Ein

    // verify energy conservation: |Er|² + |Et|² = |Ein|²
    let incident_power = incident.mag.powi(2);
    let reflected_power = reflected.mag.powi(2);
    let transmitted_power = transmitted.mag.powi(2);
    let total_power = reflected_power + transmitted_power;

    assert!((total_power - incident_power).abs() < 1e-10); // power conserved
    assert!((reflected_power / incident_power - reflectivity).abs() < 1e-10); // R test
    assert!((transmitted_power / incident_power - transmissivity).abs() < 1e-10); // T test

    // phase relationships preserved through splitting
    assert_eq!(reflected.angle, incident.angle); // reflection preserves phase
    assert_eq!(transmitted.angle, incident.angle); // transmission preserves phase

    // test different reflectivity values
    let high_reflector: f64 = 0.9; // 90% reflective coating
    let hr_reflected = incident.scale(high_reflector.sqrt());
    let hr_transmitted = incident.scale((1.0 - high_reflector).sqrt());

    // verify 90/10 split
    let hr_r_power = hr_reflected.mag.powi(2);
    let hr_t_power = hr_transmitted.mag.powi(2);
    assert!((hr_r_power / incident_power - high_reflector).abs() < 1e-10);
    assert!((hr_t_power / incident_power - (1.0 - high_reflector)).abs() < 1e-10);

    // anti-reflection coating: minimal reflection
    let ar_coating: f64 = 0.02; // 2% reflection, 98% transmission
    let ar_reflected = incident.scale(ar_coating.sqrt());
    let ar_transmitted = incident.scale((1.0 - ar_coating).sqrt());

    assert!(ar_reflected.mag < 0.15); // minimal reflection
    assert!(ar_transmitted.mag > 0.98); // maximal transmission

    // wavelength dependence: angle shift represents dispersion
    let blue_incident = Geonum::new(1.0, 1.0, 6.0); // π/6, blue wavelength
    let red_incident = Geonum::new(1.0, 1.0, 3.0); // π/3, red wavelength

    // slight coating reflectivity change with wavelength
    let blue_r: f64 = 0.48; // slightly lower reflectivity for blue
    let red_r: f64 = 0.52; // slightly higher reflectivity for red

    let blue_reflected = blue_incident.scale(blue_r.sqrt());
    let red_reflected = red_incident.scale(red_r.sqrt());

    // verify wavelength-dependent behavior
    assert!(blue_reflected.mag < red_reflected.mag); // dispersion effect
    assert_ne!(blue_reflected.angle, red_reflected.angle); // different angles

    // polarization dependence: s and p polarization at non-normal incidence
    // Fresnel equations: Rs ≠ Rp at oblique angles
    let s_polarized = Geonum::new(1.0, 1.0, 8.0); // π/8, s-polarization
    let p_polarized = Geonum::new(1.0, 3.0, 8.0); // 3π/8, p-polarization

    // different reflectivities for s and p components (Fresnel reflection)
    let rs: f64 = 0.6; // higher s-polarization reflectivity
    let rp: f64 = 0.4; // lower p-polarization reflectivity

    let s_reflected = s_polarized.scale(rs.sqrt());
    let p_reflected = p_polarized.scale(rp.sqrt());

    // verify polarization dependence
    assert!(s_reflected.mag > p_reflected.mag); // s reflects more than p
    assert_ne!(s_reflected.angle, p_reflected.angle); // different polarization angles

    // Brewster angle: p-polarization transmission maximum
    // at Brewster angle, Rp = 0, Tp = 1
    let brewster_p = Geonum::new(1.0, 0.0, 1.0); // p-pol at Brewster angle
    let brewster_reflected = brewster_p.scale(0.0); // Rp = 0
    let brewster_transmitted = brewster_p.scale(1.0); // Tp = 1

    assert_eq!(brewster_reflected.mag, 0.0); // no p-polarized reflection
    assert_eq!(brewster_transmitted.mag, 1.0); // complete p-polarized transmission

    // interference between reflected beams: coherent addition
    let coherent_beam1 = Geonum::new(0.7, 0.0, 1.0); // beam 1
    let coherent_beam2 = Geonum::new(0.7, 1.0, 1.0); // beam 2, π phase shift

    // coherent combination: amplitudes add with phase consideration
    let interfered = coherent_beam1 + coherent_beam2;

    // destructive interference when beams are π out of phase
    assert!(interfered.mag < coherent_beam1.mag); // reduced amplitude

    // multiple beam splitter cascade: each split preserves energy
    let second_splitter_r: f64 = 0.3;
    let cascade_reflected = transmitted.scale(second_splitter_r.sqrt());
    let cascade_transmitted = transmitted.scale((1.0 - second_splitter_r).sqrt());

    // verify cascade energy conservation
    let cascade_total =
        reflected.mag.powi(2) + cascade_reflected.mag.powi(2) + cascade_transmitted.mag.powi(2);
    assert!((cascade_total - incident_power).abs() < 1e-10);

    // beam splitter as interferometer element
    // Mach-Zehnder configuration: split → phase delay → recombine
    let path_delay = Angle::new(1.0, 8.0); // π/8 phase delay in one arm
    let delayed_transmitted = transmitted.rotate(path_delay);
    let recombined = reflected + delayed_transmitted; // coherent recombination

    // interference pattern depends on path difference
    assert!(recombined.mag != incident.mag); // interference modifies amplitude
    assert!(recombined.angle.rem() > 0.0); // phase relationship encoded

    // traditional: Jones matrices for polarization, Fresnel equations for reflection
    // Mueller matrices for incoherent light, ABCD matrix propagation through systems
    // geonum: amplitude scaling with angle preservation eliminates matrix formalism
}

#[test]
fn its_lens_design_optimization() {
    // traditional: lens optimization requires ray tracing + numerical gradient estimation
    // finite difference: ∂(merit_function)/∂(parameter) ≈ [f(x+δ) - f(x)]/δ
    // thousands of rays traced through perturbed systems to estimate sensitivities
    // ZEMAX, Code V use Monte Carlo + Levenberg-Marquardt for iterative optimization

    // geonum: exact gradients through geometric differentiation - no ray tracing needed
    // differentiate() gives true sensitivity direction via π/2 rotation in parameter space
    // optimization becomes navigation in angle space toward better configurations

    // EDUCATIONAL NOTE: geonum's automatic differentiation works because:
    // - differentiation IS π/2 rotation in geometric space (like sin → cos)
    // - no approximations needed - the calculus is built into angle arithmetic
    // - traditional finite differences estimate what geonum computes exactly

    // encode optical system: angle represents optical path, length represents performance metric
    let focal_length: f64 = 100.0; // 100mm design parameter
    let system_error = 0.1; // current aberration level
    let optical_path_angle = 1.0 / focal_length; // optical power in angle

    let lens_system = Geonum::new(system_error, optical_path_angle, 1.0);
    println!(
        "initial system: error={:.3}, optical_angle={:.6} rad",
        lens_system.mag,
        lens_system.angle.grade_angle()
    );

    // automatic differentiation: get exact sensitivity direction
    // this is the KEY insight - differentiate() gives the true gradient, not an approximation
    let gradient = lens_system.differentiate(); // π/2 rotation gives exact sensitivity

    println!(
        "gradient direction: magnitude={:.6}, angle={:.6} rad",
        gradient.mag,
        gradient.angle.grade_angle()
    );

    // optimization step: use gradient to compute correction direction
    // in traditional optimization: parameter -= learning_rate * gradient
    // in geonum: gradient at higher blade gives optimization direction through geometric operations
    let gradient_base = gradient.base_angle(); // reset blade while preserving geometric relationships
    let optimization_direction = gradient_base - lens_system; // direction toward better configuration
    let learning_rate = 0.1;

    let optimized_system = lens_system + optimization_direction.scale(learning_rate);
    println!(
        "optimized system: error={:.6}, optical_angle={:.6} rad",
        optimized_system.mag,
        optimized_system.angle.grade_angle()
    );

    // verify optimization reduces error (length represents error magnitude)
    assert!(
        optimized_system.mag < lens_system.mag,
        "optimization reduces error"
    );

    // multi-parameter optimization: compound lens system
    let lens1_power = 1.0 / 50.0; // 50mm element
    let lens2_power = 1.0 / 200.0; // 200mm element
    let spacing_error = 0.05; // alignment error

    // encode system as combination of elements
    let element1 = Geonum::new(spacing_error, lens1_power, 1.0);
    let element2 = Geonum::new(spacing_error, lens2_power, 1.0);
    let compound_system = element1 * element2; // combined system

    println!(
        "compound system: error={:.6}, combined_power={:.6}",
        compound_system.mag,
        compound_system.angle.grade_angle()
    );

    // system-level gradient: automatic differentiation of composed system
    let system_gradient = compound_system.differentiate();

    // optimization preserves the geometric relationships while reducing error
    let system_gradient_base = system_gradient.base_angle();
    let system_direction = system_gradient_base - compound_system;
    let optimized_compound = compound_system + system_direction.scale(0.05);

    assert!(
        optimized_compound.mag < compound_system.mag,
        "system optimization improves performance"
    );

    // aberration correction through gradient descent
    // traditional: compute Zernike coefficients, optimize aspheric parameters
    // geonum: navigate in angle space toward configurations with lower aberration

    let mut current_system = lens_system;
    let target_error = 0.01; // design specification
    let mut iteration = 0;

    while current_system.mag > target_error && iteration < 15 {
        let current_gradient = current_system.differentiate();
        let gradient_base = current_gradient.base_angle();
        let optimization_direction = gradient_base - current_system;

        // adaptive step size: larger corrections when far from target
        let step_size = (current_system.mag / target_error * 0.1).min(0.2);

        current_system = current_system + optimization_direction.scale(step_size);
        iteration += 1;

        println!("iteration {}: error={:.6}", iteration, current_system.mag);
    }

    assert!(
        current_system.mag <= target_error,
        "optimization converged to specification"
    );
    println!(
        "converged in {} iterations to error={:.6}",
        iteration, current_system.mag
    );

    // tolerance analysis: manufacturing sensitivity
    // traditional: Monte Carlo with perturbed parameters
    // geonum: exact sensitivity from differentiate()

    let manufacturing_tolerance = 0.01; // ±0.01mm focal length variation
    let sensitivity = gradient.mag; // how much error changes per unit parameter change
    let performance_variation = sensitivity * manufacturing_tolerance;

    println!("manufacturing sensitivity: {:.6} error/mm", sensitivity);
    println!(
        "tolerance impact: ±{:.6} error for ±{:.2}mm variation",
        performance_variation, manufacturing_tolerance
    );

    assert!(
        performance_variation < 0.1,
        "design robust to manufacturing tolerances"
    );

    // PERFORMANCE COMPARISON with traditional methods:

    // traditional ray tracing optimization:
    // - 10,000 rays × 20 surfaces × 50 parameters = 10M ray-surface intersections
    // - finite difference requires 2× evaluations per parameter = 20M operations
    // - optimization needs 100+ iterations = 2B+ total operations

    // geonum optimization:
    // - encode system: O(1)
    // - differentiate(): O(1) exact gradient
    // - optimize: O(1) per iteration
    // - total: O(iterations) = O(10) for this example

    let traditional_operations = 2_000_000_000u64; // 2 billion ray operations
    let geonum_operations = 10u64; // 10 iterations
    let speedup = traditional_operations / geonum_operations;

    println!(
        "traditional ray tracing: {} operations",
        traditional_operations
    );
    println!("geonum optimization: {} operations", geonum_operations);
    println!("speedup: {}× faster", speedup);

    // chromatic optimization: wavelength-dependent correction
    // traditional: optimize for multiple wavelengths simultaneously
    // geonum: wavelength variations encoded in angle relationships

    let wavelength_variation = 0.02; // dispersion effect
    let chromatic_system =
        Geonum::new(system_error, optical_path_angle + wavelength_variation, 1.0);
    let chromatic_gradient = chromatic_system.differentiate();

    // achromatic correction: balance chromatic errors across wavelengths
    let chromatic_gradient_base = chromatic_gradient.base_angle();
    let combined_direction = (gradient_base + chromatic_gradient_base).scale(0.5); // average correction
    let achromatic_direction = combined_direction - lens_system;
    let achromatic_system = lens_system + achromatic_direction.scale(0.1);

    println!(
        "achromatic optimization: error={:.6}",
        achromatic_system.mag
    );
    assert!(
        achromatic_system.mag < lens_system.mag,
        "chromatic correction improves system"
    );

    // EDUCATIONAL SUMMARY:
    // 1. geonum's differentiate() gives exact gradients, not finite difference approximations
    // 2. optimization navigates in angle space using geometric calculus
    // 3. no ray tracing needed - sensitivities computed directly from system encoding
    // 4. scales to arbitrary complexity with O(1) gradient computation
    // 5. traditional lens design computational complexity eliminated through geometric representation

    // traditional: finite difference ray tracing, numerical optimization, iterative parameter search
    // geonum: exact geometric gradients, direct angle space navigation, automatic differentiation
}
