use super::*;

#[test]
fn test_shape_t() {
    let mut shape = Shape::new_t();

    let expected_up = "010\n\
                       111\n\
                       000\n";

    let expected_right = "010\n\
                          011\n\
                          010\n";

    let expected_down = "000\n\
                         111\n\
                         010\n";

    let expected_left = "010\n\
                         110\n\
                         010\n";

    assert_eq!(shape.as_ascii(), expected_up);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_right);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_down);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_left);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_up);
}

#[test]
fn test_shape_i() {
    let mut shape = Shape::new_i();

    let expected_up = "1\n\
                       1\n\
                       1\n\
                       1\n";

    let expected_right = "1111\n";

    let expected_down = "1\n\
                         1\n\
                         1\n\
                         1\n";

    let expected_left = "1111\n";

    assert_eq!(shape.as_ascii(), expected_up);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_right);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_down);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_left);
    shape = shape.rotated();
    assert_eq!(shape.as_ascii(), expected_up);
}

#[test]
fn test_coordinates() {
    let shape = Shape::new_t();

    let center = GridPosition { x: 5, y: 5 };

    let actual: Vec<Result<GridPosition, OutOfBoundsError>> = shape.coordinates(&center).collect();

    let expected: Vec<Result<GridPosition, OutOfBoundsError>> = vec![
        Ok((4, 5).into()),
        Ok((5, 5).into()),
        Ok((6, 5).into()),
        Ok((5, 6).into()),
    ];

    assert_eq!(shape.layout.center(), (1, 1));

    assert_eq!(actual, expected);
}

#[test]
fn test_height() {
    // todo: should be 2 for t piece
    assert_eq!(Shape::new_t().height(), 3);
    assert_eq!(Shape::new_i().height(), 4);
    assert_eq!(Shape::new_l().height(), 3);
}

#[test]
fn test_shape_block_layout_rotation() {
    {
        let actual = ShapeBlockLayout {
            inner: vec![vec![0, 0, 1]],
        }
        .rotated();
        let expected = ShapeBlockLayout {
            inner: vec![vec![0], vec![0], vec![1]],
        };
        assert_eq!(expected, actual);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![vec![1, 2, 3], vec![4, 5, 6]],
        }
        .rotated();
        let expected = ShapeBlockLayout {
            inner: vec![vec![4, 1], vec![5, 2], vec![6, 3]],
        };
        assert_eq!(expected, actual);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![vec![1, 2, 3], vec![4, 5, 6]],
        }
        .rotated();
        let expected = ShapeBlockLayout {
            inner: vec![vec![4, 1], vec![5, 2], vec![6, 3]],
        };
        assert_eq!(expected, actual);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![
                vec![1, 2, 3, 4],
                vec![5, 6, 7, 8],
                vec![9, 10, 11, 12],
                vec![13, 14, 15, 16],
            ],
        }
        .rotated();
        let expected = ShapeBlockLayout {
            inner: vec![
                vec![13, 9, 5, 1],
                vec![14, 10, 6, 2],
                vec![15, 11, 7, 3],
                vec![16, 12, 8, 4],
            ],
        };
        assert_eq!(expected, actual);
    }
}

#[test]
fn test_shape_block_center() {
    {
        let actual = ShapeBlockLayout {
            inner: vec![
                vec![0],
                vec![0],
                vec![0],
            ]
        }.center();

        let expected = (0, 1);

        assert_eq!(actual, expected);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![
                vec![0],
                vec![0],
                vec![0],
                vec![0],
            ]
        }.center();

        let expected = (0, 2);

        assert_eq!(actual, expected);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![
                vec![0, 0],
                vec![0, 0],
            ]
        }.center();

        let expected = (0, 1);

        assert_eq!(actual, expected);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![
                vec![0, 0, 0],
                vec![0, 0, 0],
                vec![0, 0, 0],
            ]
        }.center();

        let expected = (1, 1);

        assert_eq!(actual, expected);
    }

    {
        let actual = ShapeBlockLayout {
            inner: vec![
                vec![0, 0, 0, 0],
                vec![0, 0, 0, 0],
                vec![0, 0, 0, 0],
                vec![0, 0, 0, 0],
            ]
        }.center();

        let expected = (1, 2);

        assert_eq!(actual, expected);
    }
}
