use jcv::canvas::{Node, TextNode};
use jcv::layout::{node_bbox_in_cells, CellRect, Viewport};

fn text(id: &str, x: i32, y: i32, w: u32, h: u32) -> Node {
    Node::Text(TextNode {
        id: id.into(),
        x,
        y,
        width: w,
        height: h,
        text: String::new(),
        color: None,
    })
}

#[test]
fn node_at_origin_with_viewport_at_origin_starts_at_cell_zero() {
    let vp = Viewport::new(80, 24);
    let n = text("n1", 0, 0, 80, 32);
    let r = node_bbox_in_cells(&n, &vp).expect("node visible");
    assert_eq!(r.x, 0);
    assert_eq!(r.y, 0);
    // 80 px / 8 = 10 cells wide, 32 px / 16 = 2 cells tall (default zoom 1.0)
    assert_eq!(r.w, 10);
    assert_eq!(r.h, 2);
}

#[test]
fn node_off_screen_returns_none() {
    let vp = Viewport::new(80, 24);
    // Move node far to the right of the visible 80-cell viewport.
    let n = text("far", 10_000, 0, 80, 32);
    assert!(node_bbox_in_cells(&n, &vp).is_none());
}

#[test]
fn zoom_scales_dimensions_proportionally() {
    let mut vp = Viewport::new(200, 60);
    let n = text("n1", 0, 0, 80, 32);
    vp.set_zoom(2.0);
    let r = node_bbox_in_cells(&n, &vp).expect("visible at 2x");
    assert_eq!(r.w, 20);
    assert_eq!(r.h, 4);
    vp.set_zoom(0.5);
    let r = node_bbox_in_cells(&n, &vp).expect("visible at 0.5x");
    assert_eq!(r.w, 5);
    assert_eq!(r.h, 1);
}

#[test]
fn aspect_ratio_preserved_across_zooms() {
    let n = text("n1", 0, 0, 160, 80);
    // baseline ratio at zoom 1.0
    let mut vp = Viewport::new(200, 60);
    let r1 = node_bbox_in_cells(&n, &vp).unwrap();
    let ratio1 = r1.w as f32 / r1.h as f32;
    vp.set_zoom(2.0);
    let r2 = node_bbox_in_cells(&n, &vp).unwrap();
    let ratio2 = r2.w as f32 / r2.h as f32;
    assert!(
        (ratio1 - ratio2).abs() < 0.001,
        "ratios diverge: {ratio1} vs {ratio2}"
    );
}

#[test]
fn viewport_offset_shifts_node_position() {
    let mut vp = Viewport::new(80, 24);
    let n = text("n1", 80, 0, 80, 32); // would be at cell x=10
    vp.set_offset(10, 0);
    let r = node_bbox_in_cells(&n, &vp).expect("visible after pan");
    assert_eq!(r.x, 0);
}

#[test]
fn cell_rect_is_constructible() {
    // Sanity: the public type can be built directly for tests/snapshots.
    let r = CellRect {
        x: 1,
        y: 2,
        w: 3,
        h: 4,
    };
    assert_eq!(r.x, 1);
}
