"""
Unit tests for image_utils styling functions
"""

import pytest
from PIL import Image
from pyPhotoAlbum.image_utils import (
    apply_rounded_corners,
    apply_drop_shadow,
    create_border_image,
)


class TestApplyRoundedCorners:
    """Tests for apply_rounded_corners function"""

    def test_zero_radius_returns_same_image(self):
        """Test that 0% radius returns unchanged image"""
        img = Image.new("RGB", (100, 100), color="red")
        result = apply_rounded_corners(img, 0.0)
        assert result.size == img.size

    def test_negative_radius_returns_same_image(self):
        """Test that negative radius returns unchanged image"""
        img = Image.new("RGB", (100, 100), color="blue")
        result = apply_rounded_corners(img, -10.0)
        assert result.size == img.size

    def test_returns_rgba_image(self):
        """Test that result is RGBA mode"""
        img = Image.new("RGB", (100, 100), color="green")
        result = apply_rounded_corners(img, 10.0)
        assert result.mode == "RGBA"

    def test_preserves_size(self):
        """Test that image size is preserved"""
        img = Image.new("RGBA", (200, 150), color="yellow")
        result = apply_rounded_corners(img, 15.0)
        assert result.size == (200, 150)

    def test_corners_are_transparent(self):
        """Test that corners become transparent"""
        img = Image.new("RGB", (100, 100), color="red")
        result = apply_rounded_corners(img, 25.0)

        # Top-left corner should be transparent
        pixel = result.getpixel((0, 0))
        assert pixel[3] == 0, "Top-left corner should be transparent"

        # Top-right corner should be transparent
        pixel = result.getpixel((99, 0))
        assert pixel[3] == 0, "Top-right corner should be transparent"

        # Bottom-left corner should be transparent
        pixel = result.getpixel((0, 99))
        assert pixel[3] == 0, "Bottom-left corner should be transparent"

        # Bottom-right corner should be transparent
        pixel = result.getpixel((99, 99))
        assert pixel[3] == 0, "Bottom-right corner should be transparent"

    def test_center_is_opaque(self):
        """Test that center remains opaque"""
        img = Image.new("RGB", (100, 100), color="blue")
        result = apply_rounded_corners(img, 10.0)

        # Center pixel should be fully opaque
        pixel = result.getpixel((50, 50))
        assert pixel[3] == 255, "Center should be opaque"

    def test_50_percent_radius_creates_ellipse(self):
        """Test that 50% radius creates elliptical result"""
        img = Image.new("RGB", (100, 100), color="purple")
        result = apply_rounded_corners(img, 50.0)

        # Corner should be transparent
        assert result.getpixel((0, 0))[3] == 0

    def test_radius_clamped_to_50(self):
        """Test that radius > 50 is clamped"""
        img = Image.new("RGB", (100, 100), color="orange")
        result = apply_rounded_corners(img, 100.0)  # Should be clamped to 50

        # Should still work and not crash
        assert result.size == (100, 100)
        assert result.mode == "RGBA"

    def test_preserves_existing_rgba(self):
        """Test that existing RGBA image alpha is preserved"""
        img = Image.new("RGBA", (100, 100), (255, 0, 0, 128))  # Semi-transparent red
        result = apply_rounded_corners(img, 10.0)

        # Center should still be semi-transparent (original alpha combined with mask)
        center_pixel = result.getpixel((50, 50))
        assert center_pixel[3] == 128  # Original alpha preserved


class TestApplyDropShadow:
    """Tests for apply_drop_shadow function"""

    def test_returns_rgba_image(self):
        """Test that result is RGBA mode"""
        img = Image.new("RGB", (50, 50), color="red")
        result = apply_drop_shadow(img)
        assert result.mode == "RGBA"

    def test_expand_increases_size(self):
        """Test that expand=True increases canvas size"""
        img = Image.new("RGBA", (50, 50), color="blue")
        result = apply_drop_shadow(img, offset=(5, 5), blur_radius=3, expand=True)
        assert result.width > 50
        assert result.height > 50

    def test_no_expand_preserves_size(self):
        """Test that expand=False preserves size"""
        img = Image.new("RGBA", (50, 50), color="green")
        result = apply_drop_shadow(img, offset=(2, 2), blur_radius=3, expand=False)
        assert result.size == (50, 50)

    def test_shadow_has_correct_color(self):
        """Test that shadow uses specified color"""
        # Create image with transparent background and opaque center
        img = Image.new("RGBA", (20, 20), (0, 0, 0, 0))
        img.paste((255, 0, 0, 255), (5, 5, 15, 15))

        result = apply_drop_shadow(
            img, offset=(10, 10), blur_radius=0, shadow_color=(0, 255, 0, 255), expand=True
        )

        # Shadow should be visible in the offset area
        # The shadow color should be green
        assert result.mode == "RGBA"

    def test_zero_blur_radius(self):
        """Test that blur_radius=0 works"""
        img = Image.new("RGBA", (30, 30), (255, 0, 0, 255))
        result = apply_drop_shadow(img, blur_radius=0, expand=True)
        assert result.mode == "RGBA"
        assert result.width >= 30
        assert result.height >= 30

    def test_large_offset(self):
        """Test shadow with large offset"""
        img = Image.new("RGBA", (50, 50), (0, 0, 255, 255))
        result = apply_drop_shadow(img, offset=(20, 20), blur_radius=5, expand=True)
        assert result.width > 50 + 20
        assert result.height > 50 + 20

    def test_negative_offset(self):
        """Test shadow with negative offset (shadow above/left of image)"""
        img = Image.new("RGBA", (50, 50), (255, 255, 0, 255))
        result = apply_drop_shadow(img, offset=(-10, -10), blur_radius=2, expand=True)
        assert result.width > 50
        assert result.height > 50


class TestCreateBorderImage:
    """Tests for create_border_image function"""

    def test_returns_rgba_image(self):
        """Test that result is RGBA mode"""
        result = create_border_image(100, 100, 5)
        assert result.mode == "RGBA"

    def test_correct_size(self):
        """Test that result has correct size"""
        result = create_border_image(200, 150, 10)
        assert result.size == (200, 150)

    def test_zero_border_returns_transparent(self):
        """Test that 0 border width returns fully transparent image"""
        result = create_border_image(100, 100, 0)
        assert result.mode == "RGBA"
        # All pixels should be transparent
        for x in range(100):
            for y in range(100):
                assert result.getpixel((x, y))[3] == 0

    def test_border_color_applied(self):
        """Test that border color is applied correctly"""
        result = create_border_image(50, 50, 5, border_color=(255, 0, 0))

        # Edge pixel should be red
        edge_pixel = result.getpixel((0, 25))  # Left edge, middle
        assert edge_pixel[:3] == (255, 0, 0)
        assert edge_pixel[3] == 255  # Opaque

    def test_center_is_transparent(self):
        """Test that center is transparent"""
        result = create_border_image(100, 100, 10)

        # Center pixel should be transparent
        center_pixel = result.getpixel((50, 50))
        assert center_pixel[3] == 0

    def test_border_surrounds_image(self):
        """Test that border covers all edges"""
        result = create_border_image(50, 50, 5, border_color=(0, 255, 0))

        # Top edge
        assert result.getpixel((25, 0))[3] == 255  # Opaque
        # Bottom edge
        assert result.getpixel((25, 49))[3] == 255
        # Left edge
        assert result.getpixel((0, 25))[3] == 255
        # Right edge
        assert result.getpixel((49, 25))[3] == 255

    def test_with_corner_radius(self):
        """Test border with rounded corners"""
        result = create_border_image(100, 100, 10, border_color=(0, 0, 255), corner_radius=20)
        assert result.mode == "RGBA"
        assert result.size == (100, 100)

    def test_corner_radius_affects_transparency(self):
        """Test that corner radius creates rounded border"""
        result = create_border_image(100, 100, 10, corner_radius=25)

        # Outer corner should be transparent (outside the rounded border)
        outer_corner = result.getpixel((0, 0))
        assert outer_corner[3] == 0

    def test_large_border_width(self):
        """Test with large border width"""
        result = create_border_image(100, 100, 45)  # Very thick border
        assert result.mode == "RGBA"

        # Center should still be transparent (just a small area)
        center = result.getpixel((50, 50))
        assert center[3] == 0


class TestStylingIntegration:
    """Integration tests combining multiple styling functions"""

    def test_rounded_corners_then_shadow(self):
        """Test applying rounded corners then shadow"""
        img = Image.new("RGB", (100, 100), color="red")
        rounded = apply_rounded_corners(img, 15.0)
        result = apply_drop_shadow(rounded, offset=(5, 5), blur_radius=3, expand=True)

        assert result.mode == "RGBA"
        assert result.width > 100
        assert result.height > 100

    def test_preserve_quality_through_chain(self):
        """Test that chaining operations preserves image quality"""
        # Create a simple pattern
        img = Image.new("RGB", (80, 80), color="blue")
        img.paste((255, 0, 0), (20, 20, 60, 60))  # Red square in center

        # Apply styling chain
        result = apply_rounded_corners(img, 10.0)
        result = apply_drop_shadow(result, expand=True)

        assert result.mode == "RGBA"

    def test_small_image_styling(self):
        """Test styling on small images"""
        img = Image.new("RGB", (10, 10), color="green")
        rounded = apply_rounded_corners(img, 20.0)
        shadow = apply_drop_shadow(rounded, offset=(1, 1), blur_radius=1, expand=True)

        assert shadow.mode == "RGBA"
        assert shadow.width >= 10
        assert shadow.height >= 10

    def test_large_image_styling(self):
        """Test styling on larger images"""
        img = Image.new("RGB", (1000, 800), color="purple")
        rounded = apply_rounded_corners(img, 5.0)

        assert rounded.mode == "RGBA"
        assert rounded.size == (1000, 800)

        # Corners should be transparent
        assert rounded.getpixel((0, 0))[3] == 0
        assert rounded.getpixel((999, 0))[3] == 0

    def test_non_square_image_styling(self):
        """Test styling on non-square images"""
        img = Image.new("RGB", (200, 50), color="orange")
        rounded = apply_rounded_corners(img, 30.0)

        assert rounded.mode == "RGBA"
        assert rounded.size == (200, 50)

        # Radius should be based on shorter side (50)
        # 30% of 50 = 15 pixels radius
        assert rounded.getpixel((0, 0))[3] == 0


class TestEdgeCases:
    """Tests for edge cases and boundary conditions"""

    def test_1x1_image_rounded_corners(self):
        """Test rounded corners on 1x1 image"""
        img = Image.new("RGB", (1, 1), color="white")
        result = apply_rounded_corners(img, 50.0)
        assert result.size == (1, 1)

    def test_very_small_radius(self):
        """Test with very small radius percentage"""
        img = Image.new("RGB", (100, 100), color="cyan")
        result = apply_rounded_corners(img, 0.1)
        assert result.mode == "RGBA"

    def test_shadow_with_transparent_image(self):
        """Test shadow on fully transparent image"""
        img = Image.new("RGBA", (50, 50), (0, 0, 0, 0))
        result = apply_drop_shadow(img, expand=True)
        assert result.mode == "RGBA"

    def test_border_on_small_image(self):
        """Test border on small image (larger than border)"""
        # Use a 10x10 image with 2px border (edge case with very small image)
        result = create_border_image(10, 10, 2)
        assert result.size == (10, 10)
        assert result.mode == "RGBA"

    def test_styling_preserves_pixel_data(self):
        """Test that styling preserves underlying pixel data"""
        # Create image with known pattern
        img = Image.new("RGB", (50, 50), (0, 0, 0))
        img.putpixel((25, 25), (255, 255, 255))

        result = apply_rounded_corners(img, 5.0)

        # Center white pixel should still be white (with alpha)
        pixel = result.getpixel((25, 25))
        assert pixel[0] == 255
        assert pixel[1] == 255
        assert pixel[2] == 255
        assert pixel[3] == 255  # Opaque in center
