"""
Test mixins for FontRegistry functionality.

Provides reusable test cases for any class that uses the FontRegistry mixin.
"""

from pyWebLayout.style import FontWeight, FontStyle, TextDecoration


class FontRegistryTestMixin:
    """
    Mixin providing standard tests for FontRegistry behavior.

    Classes using this mixin must implement:
    - create_test_object() -> object with FontRegistry mixin
    """

    def create_test_object(self):
        """
        Create an instance of the object to test.
        Must be implemented by test class.
        """
        raise NotImplementedError("Test class must implement create_test_object()")

    def test_font_caching(self):
        """Test that fonts with identical properties are cached and reused."""
        obj = self.create_test_object()

        # Create font twice with same properties
        font1 = obj.get_or_create_font(
            font_size=14, colour=(
                255, 0, 0), weight=FontWeight.BOLD)
        font2 = obj.get_or_create_font(
            font_size=14, colour=(
                255, 0, 0), weight=FontWeight.BOLD)

        # Should return the same font object (cached)
        self.assertIs(font1, font2, "Fonts with identical properties should be cached")

        # Should only have one font in registry
        self.assertEqual(len(obj._fonts), 1, "Registry should contain exactly one font")

    def test_font_differentiation(self):
        """Test that fonts with different properties create separate instances."""
        obj = self.create_test_object()

        # Create fonts that differ in exactly one property each
        base_params = {'colour': (0, 0, 0), 'weight': FontWeight.NORMAL}

        font1 = obj.get_or_create_font(font_size=14, **base_params)
        font2 = obj.get_or_create_font(font_size=16, **base_params)  # Different size

        base_params2 = {'font_size': 18, 'weight': FontWeight.NORMAL}
        font3 = obj.get_or_create_font(
            colour=(255, 0, 0), **base_params2)  # Different color

        base_params3 = {'font_size': 20, 'colour': (100, 100, 100)}
        font4 = obj.get_or_create_font(
            weight=FontWeight.BOLD,
            **base_params3)  # Different weight

        # All should be different objects
        self.assertIsNot(font1, font2, "Fonts with different sizes should be distinct")
        self.assertIsNot(font1, font3, "Fonts with different colors should be distinct")
        self.assertIsNot(
            font1,
            font4,
            "Fonts with different weights should be distinct")
        self.assertIsNot(font2, font3, "Fonts should be distinct")
        self.assertIsNot(font2, font4, "Fonts should be distinct")
        self.assertIsNot(font3, font4, "Fonts should be distinct")

        # Should have 4 fonts in registry
        self.assertEqual(len(obj._fonts), 4, "Should have 4 distinct fonts")

    def test_font_properties(self):
        """Test that created fonts have the correct properties."""
        obj = self.create_test_object()

        font = obj.get_or_create_font(
            font_size=18,
            colour=(128, 64, 32),
            weight=FontWeight.BOLD,
            style=FontStyle.ITALIC,
            decoration=TextDecoration.UNDERLINE
        )

        self.assertEqual(font.font_size, 18)
        self.assertEqual(font.colour, (128, 64, 32))
        self.assertEqual(font.weight, FontWeight.BOLD)
        self.assertEqual(font.style, FontStyle.ITALIC)
        self.assertEqual(font.decoration, TextDecoration.UNDERLINE)


class FontRegistryParentDelegationTestMixin:
    """
    Test mixin for FontRegistry parent delegation functionality.

    Classes using this mixin must implement:
    - create_parent() -> parent object with FontRegistry
    - create_child(parent) -> child object with FontRegistry and parent link
    """

    def create_parent(self):
        """Create a parent object with FontRegistry. Must be implemented."""
        raise NotImplementedError("Test class must implement create_parent()")

    def create_child(self, parent):
        """Create a child object with parent reference. Must be implemented."""
        raise NotImplementedError("Test class must implement create_child(parent)")

    def test_parent_delegation(self):
        """Test that font creation delegates to parent when available."""
        parent = self.create_parent()
        child = self.create_child(parent)

        # Create font through child
        font = child.get_or_create_font(font_size=16, colour=(200, 100, 50))

        # Font should be in parent's registry, not child's
        self.assertEqual(len(parent._fonts), 1, "Font should be in parent registry")
        self.assertEqual(len(child._fonts), 0, "Font should NOT be in child registry")

        # Getting same font through child should return parent's font
        font2 = child.get_or_create_font(font_size=16, colour=(200, 100, 50))
        self.assertIs(font, font2, "Child should reuse parent's font")
