use super::*;

fn sample_mandel(alpha: f32) -> Mandelbrot {
    Mandelbrot {
        cx: -0.5,
        cy: 0.0,
        zoom: 1.0,
        max_iter: 100,
        color_a: Color::BLACK,
        color_b: Color::WHITE,
        alpha,
    }
}

fn sample_julia(alpha: f32) -> Julia {
    Julia {
        c_re: -0.8,
        c_im: 0.156,
        zoom: 1.0,
        max_iter: 90,
        color_a: Color::WHITE,
        color_b: Color::BLACK,
        alpha,
    }
}

fn sample_surface(alpha: f32) -> SphereSurface {
    SphereSurface {
        radius: 0.8,
        color: Color::rgba(1.0, 1.0, 1.0, alpha),
        u_steps: 12,
        v_steps: 8,
        thickness: 0.01,
    }
}

#[test]
fn lerp_mandelbrot_midpoint_averages_fields() {
    let a = sample_mandel(0.0);
    let b = Mandelbrot {
        cx: 0.5,
        cy: 1.0,
        zoom: 3.0,
        max_iter: 200,
        color_a: Color::WHITE,
        color_b: Color::BLACK,
        alpha: 1.0,
    };
    let m = lerp_mandelbrot(a, b, 0.5);
    assert!((m.cx - 0.0).abs() < 1e-6);
    assert!((m.cy - 0.5).abs() < 1e-6);
    assert!((m.zoom - 2.0).abs() < 1e-6);
    assert_eq!(m.max_iter, 150);
    assert!((m.alpha - 0.5).abs() < 1e-6);
    assert!((m.color_a.r - 0.5).abs() < 1e-6);
}

#[test]
fn shape_mandelbrot_set_alpha_scales_inner_alpha() {
    let mut s = Shape::Mandelbrot(sample_mandel(1.0));
    s.set_alpha(0.25);
    match s {
        Shape::Mandelbrot(m) => assert!((m.alpha - 0.25).abs() < 1e-6),
        _ => panic!("expected mandelbrot"),
    }
}

#[test]
fn shape_julia_set_alpha_scales_inner_alpha() {
    let mut s = Shape::Julia(sample_julia(1.0));
    s.set_alpha(0.25);
    match s {
        Shape::Julia(j) => assert!((j.alpha - 0.25).abs() < 1e-6),
        _ => panic!("expected julia"),
    }
}

#[test]
fn shape_sphere_surface_set_alpha_scales_inner_alpha() {
    let mut s = Shape::SphereSurface(sample_surface(1.0));
    s.set_alpha(0.25);
    match s {
        Shape::SphereSurface(surface) => assert!((surface.color.a - 0.25).abs() < 1e-6),
        _ => panic!("expected sphere surface"),
    }
}

#[test]
fn lerp_shape_mandelbrot_same_variant_interpolates() {
    let a = Shape::Mandelbrot(sample_mandel(0.0));
    let b = Shape::Mandelbrot(sample_mandel(1.0));
    let mid = lerp_shape(&a, &b, 0.5);
    match mid {
        Shape::Mandelbrot(m) => assert!((m.alpha - 0.5).abs() < 1e-6),
        _ => panic!("expected mandelbrot"),
    }
}

#[test]
fn lerp_shape_julia_same_variant_interpolates() {
    let a = Shape::Julia(sample_julia(0.0));
    let b = Shape::Julia(sample_julia(1.0));
    let mid = lerp_shape(&a, &b, 0.5);
    match mid {
        Shape::Julia(j) => assert!((j.alpha - 0.5).abs() < 1e-6),
        _ => panic!("expected julia"),
    }
}

#[test]
fn lerp_shape_surface_same_variant_interpolates() {
    let a = Shape::SphereSurface(sample_surface(0.2));
    let mut end = sample_surface(0.8);
    end.radius = 1.2;
    end.thickness = 0.03;
    let b = Shape::SphereSurface(end);
    let mid = lerp_shape(&a, &b, 0.5);
    match mid {
        Shape::SphereSurface(surface) => {
            assert!((surface.radius - 1.0).abs() < 1e-6);
            assert!((surface.thickness - 0.02).abs() < 1e-6);
            assert!((surface.color.a - 0.5).abs() < 1e-6);
        }
        _ => panic!("expected sphere surface"),
    }
}

#[test]
fn timeline_hold_with_mandelbrot_returns_it() {
    let m = sample_mandel(1.0);
    let tl = Timeline {
        segments: vec![Segment {
            start_frame: 0,
            end_frame: 5,
            base: vec![scene_shape(1, Shape::Mandelbrot(m))],
            animation: Animation::Hold {
                shapes: vec![scene_shape(1, Shape::Mandelbrot(m))],
            },
            rate: RateFunc::Linear,
        }],
        fps: 30,
        background: Color::BLACK,
        width: 64,
        height: 64,
    };
    let shapes = tl.shapes_at(2);
    assert_eq!(shapes.len(), 1);
    assert_eq!(shapes[0].id, 1);
    match shapes[0].shape {
        Shape::Mandelbrot(_) => (),
        _ => panic!("expected mandelbrot"),
    }
}
