from PIL import Image
import pytest

from yoga.image.encoders import webp


class Test_little_endian_unint32_bytes_to_python_int(object):
    def test_uint32_value(self):
        assert (
            webp.little_endian_unint32_bytes_to_python_int(b"\x78\x56\x34\x12")
            == 305419896
        )


class Test_get_riff_structure(object):
    @pytest.fixture
    def webp_image(self):
        return open("test/images/alpha.lossless.metadata.webp", "rb").read()

    def test_riff_structure(self, webp_image):
        riff = webp.get_riff_structure(webp_image)
        assert riff["formtype"] == "WEBP"
        assert riff["size"] == 11868
        assert len(riff["chunks"]) == 5
        assert riff["chunks"][0]["type"] == "VP8X"
        assert riff["chunks"][1]["type"] == "ICCP"
        assert riff["chunks"][2]["type"] == "VP8L"
        assert riff["chunks"][3]["type"] == "EXIF"
        assert riff["chunks"][4]["type"] == "XMP "


class Test_get_vp8x_info(object):
    def test_flag_icc(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_icc"] is False
        vp8x_info = webp.get_vp8x_info(
            b"\x20\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_icc"] is True

    def test_flag_alpha(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_alpha"] is False
        vp8x_info = webp.get_vp8x_info(
            b"\x10\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_alpha"] is True

    def test_flag_exif(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_exif"] is False
        vp8x_info = webp.get_vp8x_info(
            b"\x08\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_exif"] is True

    def test_flag_xmp(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_xmp"] is False
        vp8x_info = webp.get_vp8x_info(
            b"\x04\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_xmp"] is True

    def test_flag_animation(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_anim"] is False
        vp8x_info = webp.get_vp8x_info(
            b"\x02\x00\x00\x00\x00\x00\x00\x00\x00\x00"
        )
        assert vp8x_info["has_anim"] is True

    def test_canvas_width(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\xAA\xBB\xCC\x00\x00\x00"
        )
        assert vp8x_info["canvas_width"] == 0xCCBBAA + 1

    def test_canvas_height(self):
        vp8x_info = webp.get_vp8x_info(
            b"\x00\x00\x00\x00\x00\x00\x00\xAA\xBB\xCC"
        )
        assert vp8x_info["canvas_height"] == 0xCCBBAA + 1


class Test_is_lossy_webp(object):
    def test_with_lossy_webp(self):
        image_bytes = open("test/images/alpha.lossy.webp", "rb").read()
        assert webp.is_lossy_webp(image_bytes) is True

    def test_with_lossless_webp(self):
        image_bytes = open("test/images/alpha.lossless.webp", "rb").read()
        assert webp.is_lossy_webp(image_bytes) is False

    def test_with_png(self):
        image_bytes = open("test/images/alpha.png", "rb").read()
        assert webp.is_lossy_webp(image_bytes) is False


class Test_encode_lossy_webp(object):
    @pytest.mark.parametrize(
        "image_path",
        [
            "test/images/image1.jpg",
            "test/images/indexed.png",
            "test/images/grayscale.png",
        ],
    )
    def test_no_alpha(self, image_path):
        input_image = Image.open(image_path)
        output_image_bytes = webp.optimize_lossy_webp(input_image, 0.90)
        riff = webp.get_riff_structure(output_image_bytes)

        # Checks there is only wanted chunks in the file
        for chunk in riff["chunks"]:
            assert chunk["type"] in ["VP8 "]

    def test_unused_alpha(self):
        input_image = Image.open("test/images/unused-alpha.png")
        output_image_bytes = webp.optimize_lossy_webp(input_image, 0.90)
        riff = webp.get_riff_structure(output_image_bytes)

        # Checks there is only wanted chunks in the file
        for chunk in riff["chunks"]:
            assert chunk["type"] in ["VP8 "]

    @pytest.mark.parametrize(
        "image_path",
        [
            "test/images/alpha.png",
            "test/images/threshold.png",
        ],
    )
    def test_alpha(self, image_path):
        input_image = Image.open(image_path)
        output_image_bytes = webp.optimize_lossy_webp(input_image, 0.90)
        riff = webp.get_riff_structure(output_image_bytes)

        # Checks there is only wanted chunks in the file
        for chunk in riff["chunks"]:
            assert chunk["type"] in ["VP8X", "VP8 ", "ALPH"]

        # Checks that the ALPH (alpha channel) chunk is present in the file
        alph_chunk_found = False
        for chunk in riff["chunks"]:
            if chunk["type"] == "ALPH":
                alph_chunk_found = True
        assert alph_chunk_found

    @pytest.mark.parametrize(
        "image_path",
        [
            "test/images/alpha.png",
            "test/images/threshold.png",
        ],
    )
    def test_alpha_vp8x_flags(self, image_path):
        input_image = Image.open(image_path)
        output_image_bytes = webp.optimize_lossy_webp(input_image, 0.90)
        riff = webp.get_riff_structure(output_image_bytes)

        vp8x_chunk = [c for c in riff["chunks"] if c["type"] == "VP8X"][0]
        vp8x_data = output_image_bytes[
            vp8x_chunk["data_offset"] : vp8x_chunk["data_offset"]
            + vp8x_chunk["size"]
        ]
        vp8x_info = webp.get_vp8x_info(vp8x_data)
        assert vp8x_info["has_alpha"] is True
        assert vp8x_info["has_icc"] is False
        assert vp8x_info["has_exif"] is False
        assert vp8x_info["has_xmp"] is False
        assert vp8x_info["has_anim"] is False

    def test_qualiy(self):
        input_image = Image.open("test/images/alpha.png")
        output_image_bytes_100 = webp.optimize_lossy_webp(input_image, 1.00)
        output_image_bytes_50 = webp.optimize_lossy_webp(input_image, 0.50)

        assert len(output_image_bytes_50) < len(output_image_bytes_100)
