"""
Unit tests for InteractiveImage functionality.

These tests verify that InteractiveImage can properly detect taps
and trigger callbacks when used in rendered content.
"""

import unittest
import tempfile
from pathlib import Path
from PIL import Image as PILImage

from pyWebLayout.abstract.interactive_image import InteractiveImage


class TestInteractiveImage(unittest.TestCase):
    """Test InteractiveImage interaction and bounds detection"""

    def setUp(self):
        """Create a temporary test image"""
        self.temp_dir = tempfile.mkdtemp()
        self.test_image_path = Path(self.temp_dir) / "test.png"

        # Create a simple test image
        img = PILImage.new('RGB', (100, 100), color='red')
        img.save(self.test_image_path)

    def test_create_interactive_image(self):
        """Test that InteractiveImage can be created"""
        callback_called = []

        def callback(point):
            callback_called.append(point)
            return "clicked!"

        img = InteractiveImage(
            source=str(self.test_image_path),
            alt_text="Test Image",
            callback=callback
        )

        self.assertIsNotNone(img)
        self.assertEqual(img._source, str(self.test_image_path))
        self.assertEqual(img._alt_text, "Test Image")
        self.assertIsNotNone(img._callback)

    def test_interact_with_bounds_set(self):
        """Test that interaction works when bounds are properly set"""
        callback_result = []

        def callback(point):
            callback_result.append("Book selected!")
            return "/path/to/book.epub"

        img = InteractiveImage(
            source=str(self.test_image_path),
            alt_text="Test Image",
            width=100,
            height=100,
            callback=callback
        )

        # Simulate what a renderer would do: set the bounds
        img.set_rendered_bounds(origin=(50, 50), size=(100, 100))

        # Tap inside the image bounds
        result = img.interact((75, 75))

        # Should trigger callback and return result
        self.assertEqual(result, "/path/to/book.epub")
        self.assertEqual(len(callback_result), 1)

    def test_interact_outside_bounds(self):
        """Test that interaction fails when point is outside bounds"""
        callback_called = []

        def callback(point):
            callback_called.append(True)
            return "clicked!"

        img = InteractiveImage(
            source=str(self.test_image_path),
            alt_text="Test Image",
            width=100,
            height=100,
            callback=callback
        )

        # Set bounds: image at (50, 50) with size (100, 100)
        img.set_rendered_bounds(origin=(50, 50), size=(100, 100))

        # Tap outside the image bounds
        result = img.interact((25, 25))  # Above and left of image

        # Should NOT trigger callback
        self.assertIsNone(result)
        self.assertEqual(len(callback_called), 0)

    def test_in_object_detection(self):
        """Test that in_object correctly detects points inside/outside bounds"""
        img = InteractiveImage(
            source=str(self.test_image_path),
            width=100,
            height=100
        )

        # Set bounds: image at (100, 200) with size (100, 100)
        # So it occupies x: 100-200, y: 200-300
        img.set_rendered_bounds(origin=(100, 200), size=(100, 100))

        # Test points inside
        self.assertTrue(img.in_object((100, 200)))  # Top-left corner
        self.assertTrue(img.in_object((150, 250)))  # Center
        self.assertTrue(img.in_object((199, 299)))  # Bottom-right (just inside)

        # Test points outside
        self.assertFalse(img.in_object((99, 200)))   # Just left
        self.assertFalse(img.in_object((100, 199)))  # Just above
        self.assertFalse(img.in_object((200, 200)))  # Just right
        self.assertFalse(img.in_object((100, 300)))  # Just below
        self.assertFalse(img.in_object((50, 50)))    # Far away

    def test_create_and_add_to(self):
        """Test the convenience factory method"""

        def callback(point):
            return "added!"

        # Create a mock parent with children list
        class MockParent:
            def __init__(self):
                self._children = []

        parent = MockParent()

        img = InteractiveImage.create_and_add_to(
            parent,
            source=str(self.test_image_path),
            alt_text="Test",
            callback=callback
        )

        # Should be added to parent's children
        self.assertIn(img, parent._children)
        self.assertIsInstance(img, InteractiveImage)

    def test_no_callback_returns_none(self):
        """Test that interact returns None when no callback is set"""
        img = InteractiveImage(
            source=str(self.test_image_path),
            width=100,
            height=100,
            callback=None  # No callback
        )

        img.set_rendered_bounds(origin=(0, 0), size=(100, 100))

        # Tap inside bounds
        result = img.interact((50, 50))

        # Should return None (no callback to call)
        self.assertIsNone(result)

    def test_multiple_images_independent_bounds(self):
        """Test that multiple InteractiveImages have independent bounds"""
        def callback1(point):
            return "image1"

        def callback2(point):
            return "image2"

        img1 = InteractiveImage(
            source=str(
                self.test_image_path),
            width=50,
            height=50,
            callback=callback1)
        img2 = InteractiveImage(
            source=str(
                self.test_image_path),
            width=50,
            height=50,
            callback=callback2)

        # Set different bounds
        img1.set_rendered_bounds(origin=(0, 0), size=(50, 50))
        img2.set_rendered_bounds(origin=(100, 100), size=(50, 50))

        # Tap in img1's bounds
        self.assertEqual(img1.interact((25, 25)), "image1")
        self.assertIsNone(img2.interact((25, 25)))

        # Tap in img2's bounds
        self.assertIsNone(img1.interact((125, 125)))
        self.assertEqual(img2.interact((125, 125)), "image2")


if __name__ == '__main__':
    unittest.main()
