mod common;

use railroad::{Choice, Debug, Diagram, Empty, MultiChoice, Node, Stack, Terminal};

use crate::common::boxed;

fn demo_stack_with_narrow_child() -> railroad::Sequence<Box<dyn Node>> {
    railroad::Sequence::new(vec![
        boxed(railroad::SimpleStart),
        boxed(Stack::new(vec![boxed(Empty), boxed(Debug::new(5, 25, 4))])),
        boxed(railroad::SimpleEnd),
    ])
}

#[test]
fn sequence_supports_builder_style_composition() {
    let mut sequence: railroad::Sequence<Box<dyn railroad::Node>> = railroad::Sequence::default();
    sequence
        .push(boxed(railroad::Start))
        .push(boxed(Terminal::new("middle".to_owned())))
        .push(boxed(railroad::End));

    let svg = Diagram::new(sequence).to_string();

    assert!(svg.contains("class=\"sequence\""));
    assert!(svg.contains("middle"));
    assert!(svg.matches("<path").count() >= 3);
}

#[test]
fn stack_and_choice_render_container_markup_and_children() {
    let mut stack = Stack::new(vec![
        Terminal::new("top".to_owned()),
        Terminal::new("bottom".to_owned()),
    ]);
    stack
        .attr("data-layout".to_owned())
        .or_insert("stack".to_owned());
    let stack_svg = Diagram::new(stack).to_string();
    assert!(stack_svg.contains("class=\"stack\""));
    assert!(stack_svg.contains("data-layout=\"stack\""));
    assert!(stack_svg.contains("top"));
    assert!(stack_svg.contains("bottom"));

    let mut choice: Choice<Box<dyn railroad::Node>> = Choice::new(vec![
        boxed(Terminal::new("one".to_owned())),
        boxed(Terminal::new("two".to_owned())),
        boxed(Empty),
    ]);
    choice
        .attr("data-layout".to_owned())
        .or_insert("choice".to_owned());
    let choice_svg = Diagram::new(choice).to_string();
    assert!(choice_svg.contains("class=\"choice\""));
    assert!(choice_svg.contains("data-layout=\"choice\""));
    assert!(choice_svg.contains("one"));
    assert!(choice_svg.contains("two"));
    assert!(choice_svg.matches("<path").count() >= 3);
}

#[test]
fn stack_inter_child_connector_stops_at_narrow_child_entry() {
    let svg = Diagram::new(demo_stack_with_narrow_child()).to_string();

    assert!(svg.contains(
        "<path d=\" M 59 15 a 12 12 0 0 1 12 12 v 0 a 12 12 0 0 1 -12 12 h 0 a 12 12 0 0 0 -12 12 v 0 v 0 a 12 12 0 0 0 12 12\"/>"
    ));
    assert!(!svg.contains(
        "<path d=\" M 59 15 a 12 12 0 0 1 12 12 v 0 a 12 12 0 0 1 -12 12 h 0 a 12 12 0 0 0 -12 12 v 0 v 0 a 12 12 0 0 0 12 12 h 12\"/>"
    ));
    assert!(svg.contains("<rect x=\"59\" y=\"58\" height=\"25\" width=\"4\""));
}

#[test]
fn multichoice_renders_container_markup_and_children() {
    let mut multichoice: MultiChoice<Box<dyn railroad::Node>> = MultiChoice::new(vec![
        vec![
            boxed(Terminal::new("red".to_owned())),
            boxed(Terminal::new("blue".to_owned())),
        ],
        vec![boxed(Terminal::new("green".to_owned()))],
    ]);
    multichoice
        .attr("data-layout".to_owned())
        .or_insert("multichoice".to_owned());

    let svg = Diagram::new(multichoice).to_string();

    assert!(svg.contains("class=\"multichoice\""));
    assert!(svg.contains("data-layout=\"multichoice\""));
    assert!(svg.contains("red"));
    assert!(svg.contains("blue"));
    assert!(svg.contains("green"));
    assert!(svg.matches("<path").count() >= 5);
}

#[test]
fn multichoice_supports_push_column_and_into_inner() {
    let mut multichoice = MultiChoice::default();
    multichoice.push_column(vec![Terminal::new("one".to_owned())]);
    multichoice.push_column(vec![
        Terminal::new("two".to_owned()),
        Terminal::new("three".to_owned()),
    ]);

    let columns = multichoice.into_inner();

    assert_eq!(columns.len(), 2);
    assert_eq!(columns[0].len(), 1);
    assert_eq!(columns[1].len(), 2);
}

#[test]
fn multichoice_empty_and_single_column_match_choice_geometry() {
    let empty_choice: Choice<Box<dyn railroad::Node>> = Choice::new(vec![]);
    let empty_multichoice: MultiChoice<Box<dyn railroad::Node>> = MultiChoice::new(vec![]);
    assert_eq!(
        empty_multichoice.entry_height(),
        empty_choice.entry_height()
    );
    assert_eq!(empty_multichoice.height(), empty_choice.height());
    assert_eq!(empty_multichoice.width(), empty_choice.width());

    let choice: Choice<Box<dyn railroad::Node>> = Choice::new(vec![
        boxed(Terminal::new("one".to_owned())),
        boxed(Empty),
        boxed(Terminal::new("three".to_owned())),
    ]);
    let multichoice: MultiChoice<Box<dyn railroad::Node>> = MultiChoice::new(vec![vec![
        boxed(Terminal::new("one".to_owned())),
        boxed(Empty),
        boxed(Terminal::new("three".to_owned())),
    ]]);

    assert_eq!(multichoice.entry_height(), choice.entry_height());
    assert_eq!(multichoice.height(), choice.height());
    assert_eq!(multichoice.width(), choice.width());
}
