import os.path

import pytest
from PIL import Image, ImageColor, ImageDraw, ImageFont

from .helper import (
    assert_image_equal,
    assert_image_similar,
    hopper,
    skip_unless_feature,
)

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GRAY = (190, 190, 190)
DEFAULT_MODE = "RGB"
IMAGES_PATH = os.path.join("Tests", "images", "imagedraw")

# Image size
W, H = 100, 100

# Bounding box points
X0 = int(W / 4)
X1 = int(X0 * 3)
Y0 = int(H / 4)
Y1 = int(X0 * 3)

# Two kinds of bounding box
BBOX1 = [(X0, Y0), (X1, Y1)]
BBOX2 = [X0, Y0, X1, Y1]

# Two kinds of coordinate sequences
POINTS1 = [(10, 10), (20, 40), (30, 30)]
POINTS2 = [10, 10, 20, 40, 30, 30]

KITE_POINTS = [(10, 50), (70, 10), (90, 50), (70, 90), (10, 50)]


def test_sanity():
    im = hopper("RGB").copy()

    draw = ImageDraw.ImageDraw(im)
    draw = ImageDraw.Draw(im)

    draw.ellipse(list(range(4)))
    draw.line(list(range(10)))
    draw.polygon(list(range(100)))
    draw.rectangle(list(range(4)))


def test_valueerror():
    with Image.open("Tests/images/chi.gif") as im:

        draw = ImageDraw.Draw(im)
        draw.line((0, 0), fill=(0, 0, 0))


def test_mode_mismatch():
    im = hopper("RGB").copy()

    with pytest.raises(ValueError):
        ImageDraw.ImageDraw(im, mode="L")


def helper_arc(bbox, start, end):
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.arc(bbox, start, end)

    # Assert
    assert_image_similar(im, Image.open("Tests/images/imagedraw_arc.png"), 1)


def test_arc1():
    helper_arc(BBOX1, 0, 180)
    helper_arc(BBOX1, 0.5, 180.4)


def test_arc2():
    helper_arc(BBOX2, 0, 180)
    helper_arc(BBOX2, 0.5, 180.4)


def test_arc_end_le_start():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    start = 270.5
    end = 0

    # Act
    draw.arc(BBOX1, start=start, end=end)

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_arc_end_le_start.png"))


def test_arc_no_loops():
    # No need to go in loops
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    start = 5
    end = 370

    # Act
    draw.arc(BBOX1, start=start, end=end)

    # Assert
    assert_image_similar(im, Image.open("Tests/images/imagedraw_arc_no_loops.png"), 1)


def test_arc_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_arc_width.png"

    # Act
    draw.arc(BBOX1, 10, 260, width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_arc_width_pieslice_large():
    # Tests an arc with a large enough width that it is a pieslice
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_arc_width_pieslice.png"

    # Act
    draw.arc(BBOX1, 10, 260, fill="yellow", width=100)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_arc_width_fill():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_arc_width_fill.png"

    # Act
    draw.arc(BBOX1, 10, 260, fill="yellow", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_arc_width_non_whole_angle():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_arc_width_non_whole_angle.png"

    # Act
    draw.arc(BBOX1, 10, 259.5, width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_bitmap():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    with Image.open("Tests/images/pil123rgba.png") as small:
        small = small.resize((50, 50), Image.NEAREST)

        # Act
        draw.bitmap((10, 10), small)

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_bitmap.png"))


def helper_chord(mode, bbox, start, end):
    # Arrange
    im = Image.new(mode, (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_chord_{}.png".format(mode)

    # Act
    draw.chord(bbox, start, end, fill="red", outline="yellow")

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_chord1():
    for mode in ["RGB", "L"]:
        helper_chord(mode, BBOX1, 0, 180)
        helper_chord(mode, BBOX1, 0.5, 180.4)


def test_chord2():
    for mode in ["RGB", "L"]:
        helper_chord(mode, BBOX2, 0, 180)
        helper_chord(mode, BBOX2, 0.5, 180.4)


def test_chord_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_chord_width.png"

    # Act
    draw.chord(BBOX1, 10, 260, outline="yellow", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_chord_width_fill():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_chord_width_fill.png"

    # Act
    draw.chord(BBOX1, 10, 260, fill="red", outline="yellow", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_chord_zero_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.chord(BBOX1, 10, 260, fill="red", outline="yellow", width=0)

    # Assert
    with Image.open("Tests/images/imagedraw_chord_zero_width.png") as expected:
        assert_image_equal(im, expected)


def helper_ellipse(mode, bbox):
    # Arrange
    im = Image.new(mode, (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_ellipse_{}.png".format(mode)

    # Act
    draw.ellipse(bbox, fill="green", outline="blue")

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_ellipse1():
    for mode in ["RGB", "L"]:
        helper_ellipse(mode, BBOX1)


def test_ellipse2():
    for mode in ["RGB", "L"]:
        helper_ellipse(mode, BBOX2)


def test_ellipse_translucent():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im, "RGBA")

    # Act
    draw.ellipse(BBOX1, fill=(0, 255, 0, 127))

    # Assert
    expected = Image.open("Tests/images/imagedraw_ellipse_translucent.png")
    assert_image_similar(im, expected, 1)


def test_ellipse_edge():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.ellipse(((0, 0), (W - 1, H)), fill="white")

    # Assert
    assert_image_similar(im, Image.open("Tests/images/imagedraw_ellipse_edge.png"), 1)


def test_ellipse_symmetric():
    for bbox in [(25, 25, 76, 76), (25, 25, 75, 75)]:
        im = Image.new("RGB", (101, 101))
        draw = ImageDraw.Draw(im)
        draw.ellipse(bbox, fill="green", outline="blue")
        assert_image_equal(im, im.transpose(Image.FLIP_LEFT_RIGHT))


def test_ellipse_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_ellipse_width.png"

    # Act
    draw.ellipse(BBOX1, outline="blue", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_ellipse_width_large():
    # Arrange
    im = Image.new("RGB", (500, 500))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_ellipse_width_large.png"

    # Act
    draw.ellipse((25, 25, 475, 475), outline="blue", width=75)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_ellipse_width_fill():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_ellipse_width_fill.png"

    # Act
    draw.ellipse(BBOX1, fill="green", outline="blue", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_ellipse_zero_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.ellipse(BBOX1, fill="green", outline="blue", width=0)

    # Assert
    with Image.open("Tests/images/imagedraw_ellipse_zero_width.png") as expected:
        assert_image_equal(im, expected)


def helper_line(points):
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.line(points, fill="yellow", width=2)

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_line.png"))


def test_line1():
    helper_line(POINTS1)


def test_line2():
    helper_line(POINTS2)


def test_shape1():
    # Arrange
    im = Image.new("RGB", (100, 100), "white")
    draw = ImageDraw.Draw(im)
    x0, y0 = 5, 5
    x1, y1 = 5, 50
    x2, y2 = 95, 50
    x3, y3 = 95, 5

    # Act
    s = ImageDraw.Outline()
    s.move(x0, y0)
    s.curve(x1, y1, x2, y2, x3, y3)
    s.line(x0, y0)

    draw.shape(s, fill=1)

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_shape1.png"))


def test_shape2():
    # Arrange
    im = Image.new("RGB", (100, 100), "white")
    draw = ImageDraw.Draw(im)
    x0, y0 = 95, 95
    x1, y1 = 95, 50
    x2, y2 = 5, 50
    x3, y3 = 5, 95

    # Act
    s = ImageDraw.Outline()
    s.move(x0, y0)
    s.curve(x1, y1, x2, y2, x3, y3)
    s.line(x0, y0)

    draw.shape(s, outline="blue")

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_shape2.png"))


def helper_pieslice(bbox, start, end):
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.pieslice(bbox, start, end, fill="white", outline="blue")

    # Assert
    assert_image_similar(im, Image.open("Tests/images/imagedraw_pieslice.png"), 1)


def test_pieslice1():
    helper_pieslice(BBOX1, -90, 45)
    helper_pieslice(BBOX1, -90.5, 45.4)


def test_pieslice2():
    helper_pieslice(BBOX2, -90, 45)
    helper_pieslice(BBOX2, -90.5, 45.4)


def test_pieslice_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_pieslice_width.png"

    # Act
    draw.pieslice(BBOX1, 10, 260, outline="blue", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_pieslice_width_fill():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_pieslice_width_fill.png"

    # Act
    draw.pieslice(BBOX1, 10, 260, fill="white", outline="blue", width=5)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_pieslice_zero_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.pieslice(BBOX1, 10, 260, fill="white", outline="blue", width=0)

    # Assert
    with Image.open("Tests/images/imagedraw_pieslice_zero_width.png") as expected:
        assert_image_equal(im, expected)


def helper_point(points):
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.point(points, fill="yellow")

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_point.png"))


def test_point1():
    helper_point(POINTS1)


def test_point2():
    helper_point(POINTS2)


def helper_polygon(points):
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.polygon(points, fill="red", outline="blue")

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_polygon.png"))


def test_polygon1():
    helper_polygon(POINTS1)


def test_polygon2():
    helper_polygon(POINTS2)


def test_polygon_kite():
    # Test drawing lines of different gradients (dx>dy, dy>dx) and
    # vertical (dx==0) and horizontal (dy==0) lines
    for mode in ["RGB", "L"]:
        # Arrange
        im = Image.new(mode, (W, H))
        draw = ImageDraw.Draw(im)
        expected = "Tests/images/imagedraw_polygon_kite_{}.png".format(mode)

        # Act
        draw.polygon(KITE_POINTS, fill="blue", outline="yellow")

        # Assert
        assert_image_equal(im, Image.open(expected))


def helper_rectangle(bbox):
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.rectangle(bbox, fill="black", outline="green")

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_rectangle.png"))


def test_rectangle1():
    helper_rectangle(BBOX1)


def test_rectangle2():
    helper_rectangle(BBOX2)


def test_big_rectangle():
    # Test drawing a rectangle bigger than the image
    # Arrange
    im = Image.new("RGB", (W, H))
    bbox = [(-1, -1), (W + 1, H + 1)]
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_big_rectangle.png"

    # Act
    draw.rectangle(bbox, fill="orange")

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_rectangle_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_rectangle_width.png"

    # Act
    draw.rectangle(BBOX1, outline="green", width=5)

    # Assert
    assert_image_equal(im, Image.open(expected))


def test_rectangle_width_fill():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_rectangle_width_fill.png"

    # Act
    draw.rectangle(BBOX1, fill="blue", outline="green", width=5)

    # Assert
    assert_image_equal(im, Image.open(expected))


def test_rectangle_zero_width():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.rectangle(BBOX1, fill="blue", outline="green", width=0)

    # Assert
    with Image.open("Tests/images/imagedraw_rectangle_zero_width.png") as expected:
        assert_image_equal(im, expected)


def test_rectangle_I16():
    # Arrange
    im = Image.new("I;16", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    draw.rectangle(BBOX1, fill="black", outline="green")

    # Assert
    assert_image_equal(
        im.convert("I"), Image.open("Tests/images/imagedraw_rectangle_I.png")
    )


def test_floodfill():
    red = ImageColor.getrgb("red")

    for mode, value in [("L", 1), ("RGBA", (255, 0, 0, 0)), ("RGB", red)]:
        # Arrange
        im = Image.new(mode, (W, H))
        draw = ImageDraw.Draw(im)
        draw.rectangle(BBOX2, outline="yellow", fill="green")
        centre_point = (int(W / 2), int(H / 2))

        # Act
        ImageDraw.floodfill(im, centre_point, value)

        # Assert
        expected = "Tests/images/imagedraw_floodfill_" + mode + ".png"
        with Image.open(expected) as im_floodfill:
            assert_image_equal(im, im_floodfill)

    # Test that using the same colour does not change the image
    ImageDraw.floodfill(im, centre_point, red)
    assert_image_equal(im, im_floodfill)

    # Test that filling outside the image does not change the image
    ImageDraw.floodfill(im, (W, H), red)
    assert_image_equal(im, im_floodfill)

    # Test filling at the edge of an image
    im = Image.new("RGB", (1, 1))
    ImageDraw.floodfill(im, (0, 0), red)
    assert_image_equal(im, Image.new("RGB", (1, 1), red))


def test_floodfill_border():
    # floodfill() is experimental

    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    draw.rectangle(BBOX2, outline="yellow", fill="green")
    centre_point = (int(W / 2), int(H / 2))

    # Act
    ImageDraw.floodfill(
        im, centre_point, ImageColor.getrgb("red"), border=ImageColor.getrgb("black"),
    )

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_floodfill2.png"))


def test_floodfill_thresh():
    # floodfill() is experimental

    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    draw.rectangle(BBOX2, outline="darkgreen", fill="green")
    centre_point = (int(W / 2), int(H / 2))

    # Act
    ImageDraw.floodfill(im, centre_point, ImageColor.getrgb("red"), thresh=30)

    # Assert
    assert_image_equal(im, Image.open("Tests/images/imagedraw_floodfill2.png"))


def test_floodfill_not_negative():
    # floodfill() is experimental
    # Test that floodfill does not extend into negative coordinates

    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    draw.line((W / 2, 0, W / 2, H / 2), fill="green")
    draw.line((0, H / 2, W / 2, H / 2), fill="green")

    # Act
    ImageDraw.floodfill(im, (int(W / 4), int(H / 4)), ImageColor.getrgb("red"))

    # Assert
    assert_image_equal(
        im, Image.open("Tests/images/imagedraw_floodfill_not_negative.png")
    )


def create_base_image_draw(
    size, mode=DEFAULT_MODE, background1=WHITE, background2=GRAY
):
    img = Image.new(mode, size, background1)
    for x in range(0, size[0]):
        for y in range(0, size[1]):
            if (x + y) % 2 == 0:
                img.putpixel((x, y), background2)
    return img, ImageDraw.Draw(img)


def test_square():
    with Image.open(os.path.join(IMAGES_PATH, "square.png")) as expected:
        expected.load()
        img, draw = create_base_image_draw((10, 10))
        draw.polygon([(2, 2), (2, 7), (7, 7), (7, 2)], BLACK)
        assert_image_equal(img, expected, "square as normal polygon failed")
        img, draw = create_base_image_draw((10, 10))
        draw.polygon([(7, 7), (7, 2), (2, 2), (2, 7)], BLACK)
        assert_image_equal(img, expected, "square as inverted polygon failed")
        img, draw = create_base_image_draw((10, 10))
        draw.rectangle((2, 2, 7, 7), BLACK)
        assert_image_equal(img, expected, "square as normal rectangle failed")
        img, draw = create_base_image_draw((10, 10))
        draw.rectangle((7, 7, 2, 2), BLACK)
        assert_image_equal(img, expected, "square as inverted rectangle failed")


def test_triangle_right():
    with Image.open(os.path.join(IMAGES_PATH, "triangle_right.png")) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.polygon([(3, 5), (17, 5), (10, 12)], BLACK)
        assert_image_equal(img, expected, "triangle right failed")


def test_line_horizontal():
    with Image.open(
        os.path.join(IMAGES_PATH, "line_horizontal_w2px_normal.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 14, 5), BLACK, 2)
        assert_image_equal(
            img, expected, "line straight horizontal normal 2px wide failed"
        )
    with Image.open(
        os.path.join(IMAGES_PATH, "line_horizontal_w2px_inverted.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((14, 5, 5, 5), BLACK, 2)
        assert_image_equal(
            img, expected, "line straight horizontal inverted 2px wide failed"
        )
    with Image.open(os.path.join(IMAGES_PATH, "line_horizontal_w3px.png")) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 14, 5), BLACK, 3)
        assert_image_equal(
            img, expected, "line straight horizontal normal 3px wide failed"
        )
        img, draw = create_base_image_draw((20, 20))
        draw.line((14, 5, 5, 5), BLACK, 3)
        assert_image_equal(
            img, expected, "line straight horizontal inverted 3px wide failed"
        )
    with Image.open(
        os.path.join(IMAGES_PATH, "line_horizontal_w101px.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((200, 110))
        draw.line((5, 55, 195, 55), BLACK, 101)
        assert_image_equal(img, expected, "line straight horizontal 101px wide failed")


def test_line_h_s1_w2():
    pytest.skip("failing")
    with Image.open(
        os.path.join(IMAGES_PATH, "line_horizontal_slope1px_w2px.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 14, 6), BLACK, 2)
        assert_image_equal(img, expected, "line horizontal 1px slope 2px wide failed")


def test_line_vertical():
    with Image.open(
        os.path.join(IMAGES_PATH, "line_vertical_w2px_normal.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 5, 14), BLACK, 2)
        assert_image_equal(
            img, expected, "line straight vertical normal 2px wide failed"
        )
    with Image.open(
        os.path.join(IMAGES_PATH, "line_vertical_w2px_inverted.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 14, 5, 5), BLACK, 2)
        assert_image_equal(
            img, expected, "line straight vertical inverted 2px wide failed"
        )
    with Image.open(os.path.join(IMAGES_PATH, "line_vertical_w3px.png")) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 5, 14), BLACK, 3)
        assert_image_equal(
            img, expected, "line straight vertical normal 3px wide failed"
        )
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 14, 5, 5), BLACK, 3)
        assert_image_equal(
            img, expected, "line straight vertical inverted 3px wide failed"
        )
    with Image.open(os.path.join(IMAGES_PATH, "line_vertical_w101px.png")) as expected:
        expected.load()
        img, draw = create_base_image_draw((110, 200))
        draw.line((55, 5, 55, 195), BLACK, 101)
        assert_image_equal(img, expected, "line straight vertical 101px wide failed")
    with Image.open(
        os.path.join(IMAGES_PATH, "line_vertical_slope1px_w2px.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 6, 14), BLACK, 2)
        assert_image_equal(img, expected, "line vertical 1px slope 2px wide failed")


def test_line_oblique_45():
    with Image.open(
        os.path.join(IMAGES_PATH, "line_oblique_45_w3px_a.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 5, 14, 14), BLACK, 3)
        assert_image_equal(img, expected, "line oblique 45 normal 3px wide A failed")
        img, draw = create_base_image_draw((20, 20))
        draw.line((14, 14, 5, 5), BLACK, 3)
        assert_image_equal(img, expected, "line oblique 45 inverted 3px wide A failed")
    with Image.open(
        os.path.join(IMAGES_PATH, "line_oblique_45_w3px_b.png")
    ) as expected:
        expected.load()
        img, draw = create_base_image_draw((20, 20))
        draw.line((14, 5, 5, 14), BLACK, 3)
        assert_image_equal(img, expected, "line oblique 45 normal 3px wide B failed")
        img, draw = create_base_image_draw((20, 20))
        draw.line((5, 14, 14, 5), BLACK, 3)
        assert_image_equal(img, expected, "line oblique 45 inverted 3px wide B failed")


def test_wide_line_dot():
    # Test drawing a wide "line" from one point to another just draws a single point
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_wide_line_dot.png"

    # Act
    draw.line([(50, 50), (50, 50)], width=3)

    # Assert
    assert_image_similar(im, Image.open(expected), 1)


def test_line_joint():
    im = Image.new("RGB", (500, 325))
    draw = ImageDraw.Draw(im)
    expected = "Tests/images/imagedraw_line_joint_curve.png"

    # Act
    xy = [
        (400, 280),
        (380, 280),
        (450, 280),
        (440, 120),
        (350, 200),
        (310, 280),
        (300, 280),
        (250, 280),
        (250, 200),
        (150, 200),
        (150, 260),
        (50, 200),
        (150, 50),
        (250, 100),
    ]
    draw.line(xy, GRAY, 50, "curve")

    # Assert
    assert_image_similar(im, Image.open(expected), 3)


def test_textsize_empty_string():
    # https://github.com/python-pillow/Pillow/issues/2783
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)

    # Act
    # Should not cause 'SystemError: <built-in method getsize of
    # ImagingFont object at 0x...> returned NULL without setting an error'
    draw.textsize("")
    draw.textsize("\n")
    draw.textsize("test\n")


@skip_unless_feature("freetype2")
def test_textsize_stroke():
    # Arrange
    im = Image.new("RGB", (W, H))
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 20)

    # Act / Assert
    assert draw.textsize("A", font, stroke_width=2) == (16, 20)
    assert draw.multiline_textsize("ABC\nAaaa", font, stroke_width=2) == (52, 44)


@skip_unless_feature("freetype2")
def test_stroke():
    for suffix, stroke_fill in {"same": None, "different": "#0f0"}.items():
        # Arrange
        im = Image.new("RGB", (120, 130))
        draw = ImageDraw.Draw(im)
        font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)

        # Act
        draw.text((10, 10), "A", "#f00", font, stroke_width=2, stroke_fill=stroke_fill)

        # Assert
        assert_image_similar(
            im, Image.open("Tests/images/imagedraw_stroke_" + suffix + ".png"), 3.1
        )


@skip_unless_feature("freetype2")
def test_stroke_multiline():
    # Arrange
    im = Image.new("RGB", (100, 250))
    draw = ImageDraw.Draw(im)
    font = ImageFont.truetype("Tests/fonts/FreeMono.ttf", 120)

    # Act
    draw.multiline_text(
        (10, 10), "A\nB", "#f00", font, stroke_width=2, stroke_fill="#0f0"
    )

    # Assert
    assert_image_similar(
        im, Image.open("Tests/images/imagedraw_stroke_multiline.png"), 3.3
    )


def test_same_color_outline():
    # Prepare shape
    x0, y0 = 5, 5
    x1, y1 = 5, 50
    x2, y2 = 95, 50
    x3, y3 = 95, 5

    s = ImageDraw.Outline()
    s.move(x0, y0)
    s.curve(x1, y1, x2, y2, x3, y3)
    s.line(x0, y0)

    # Begin
    for mode in ["RGB", "L"]:
        for fill, outline in [["red", None], ["red", "red"], ["red", "#f00"]]:
            for operation, args in {
                "chord": [BBOX1, 0, 180],
                "ellipse": [BBOX1],
                "shape": [s],
                "pieslice": [BBOX1, -90, 45],
                "polygon": [[(18, 30), (85, 30), (60, 72)]],
                "rectangle": [BBOX1],
            }.items():
                # Arrange
                im = Image.new(mode, (W, H))
                draw = ImageDraw.Draw(im)

                # Act
                draw_method = getattr(draw, operation)
                args += [fill, outline]
                draw_method(*args)

                # Assert
                expected = "Tests/images/imagedraw_outline_{}_{}.png".format(
                    operation, mode
                )
                assert_image_similar(im, Image.open(expected), 1)