# Mock bpy BEFORE test collection can import src modules
import sys
from unittest.mock import Mock, MagicMock

# Create comprehensive bpy mock
bpy_mock = MagicMock()
bpy_mock.types = MagicMock()
bpy_mock.props = MagicMock()
bpy_mock.utils = MagicMock()
bpy_mock.ops = MagicMock()
bpy_mock.context = MagicMock()
bpy_mock.data = MagicMock()
bpy_mock.app = MagicMock()

# Set up mock attributes that src code needs
bpy_mock.types.Operator = Mock
bpy_mock.types.Panel = Mock
bpy_mock.types.PropertyGroup = Mock
bpy_mock.types.UIList = Mock
bpy_mock.types.Scene = Mock()
bpy_mock.types.NODE_MT_add = Mock()
bpy_mock.types.VIEW3D_MT_add = Mock()
bpy_mock.types.VIEW3D_MT_mesh_add = Mock()
bpy_mock.types.NODE_MT_node = Mock()
bpy_mock.types.IMAGE_MT_image = Mock()

bpy_mock.props.StringProperty = Mock
bpy_mock.props.IntProperty = Mock
bpy_mock.props.FloatVectorProperty = Mock
bpy_mock.props.FloatProperty = Mock
bpy_mock.props.BoolProperty = Mock
bpy_mock.props.EnumProperty = Mock
bpy_mock.props.CollectionProperty = Mock
bpy_mock.props.PointerProperty = Mock

bpy_mock.utils.register_class = Mock()
bpy_mock.utils.unregister_class = Mock()

bpy_mock.app.handlers = Mock()
bpy_mock.app.handlers.load_post = []
bpy_mock.app.handlers.persistent = lambda f: f

bpy_mock.context.window_manager = Mock()
bpy_mock.context.scene = Mock()

# Mock ALL Blender modules at import time
sys.modules['bpy'] = bpy_mock
sys.modules['bmesh'] = MagicMock()
sys.modules['mathutils'] = MagicMock()
sys.modules['bpy.types'] = bpy_mock.types
sys.modules['bpy.props'] = bpy_mock.props
sys.modules['bpy.utils'] = bpy_mock.utils
sys.modules['bpy.ops'] = bpy_mock.ops
sys.modules['bpy.app'] = bpy_mock.app
sys.modules['bpy.context'] = bpy_mock.context

"""
Pytest configuration and fixtures for Text Texture Generator tests.
Provides Blender mocking and common test utilities.
"""

import pytest
from PIL import Image, ImageDraw, ImageFont


class MockBlenderData:
    """Mock for bpy.data"""
    def __init__(self):
        self.images = MockImageCollection()


class MockImageCollection:
    """Mock for bpy.data.images collection"""
    def __init__(self):
        self._images = {}
    
    def new(self, name, width, height, alpha=True):
        """Create a new mock Blender image"""
        mock_image = MockBlenderImage(name, width, height, alpha)
        self._images[name] = mock_image
        return mock_image
    
    def remove(self, image):
        """Remove image from collection"""
        if hasattr(image, 'name') and image.name in self._images:
            del self._images[image.name]
    
    def __contains__(self, name):
        return name in self._images
    
    def __getitem__(self, name):
        return self._images[name]


class MockBlenderImage:
    """Mock for Blender image objects"""
    def __init__(self, name, width, height, alpha=True):
        self.name = name
        self.width = width
        self.height = height
        self.alpha = alpha
        self.pixels = [0.0] * (width * height * 4)  # RGBA pixels
        self.packed_file = None
    
    def pack(self):
        """Mock pack method"""
        self.packed_file = Mock()


# Attach mock data to bpy_mock
bpy_mock.data = MockBlenderData()


@pytest.fixture(autouse=True)
def mock_bpy_fixture():
    """Provide bpy mock to tests (already mocked at import time)."""
    yield bpy_mock


@pytest.fixture
def sample_font():
    """Provide a sample font for testing"""
    try:
        # Try to use default font
        return ImageFont.load_default()
    except Exception:
        # Create a minimal mock font if default fails
        mock_font = Mock()
        mock_font.getmetrics.return_value = (10, 2)  # ascent, descent
        return mock_font


@pytest.fixture
def sample_text_short():
    """Short sample text for testing"""
    return "Hello World"


@pytest.fixture
def sample_text_long():
    """Long sample text for testing text wrapping"""
    return "This is a much longer piece of text that should wrap across multiple lines when constrained by width limits."


@pytest.fixture
def sample_text_multiline():
    """Sample text containing newlines for testing"""
    return "Line 1\nLine 2\nLine 3\nLine 4"


@pytest.fixture
def standard_dimensions():
    """Standard width/height dimensions for testing"""
    return {"width": 512, "height": 512}


@pytest.fixture
def mock_pil_image():
    """Mock PIL Image for testing"""
    from unittest.mock import patch
    with patch('PIL.Image.new') as mock_new:
        mock_img = Mock()
        mock_img.size = (512, 512)
        mock_img.width = 512
        mock_img.height = 512
        mock_img.getdata.return_value = [(255, 255, 255, 255)] * (512 * 512)
        mock_img.transpose.return_value = mock_img
        mock_new.return_value = mock_img
        yield mock_img


@pytest.fixture
def mock_image_draw():
    """Mock PIL ImageDraw for testing"""
    from unittest.mock import patch
    with patch('PIL.ImageDraw.Draw') as mock_draw_class:
        mock_draw = Mock()
        mock_draw.textbbox.return_value = (0, 0, 100, 20)  # x1, y1, x2, y2
        mock_draw.text.return_value = None
        mock_draw_class.return_value = mock_draw
        yield mock_draw


@pytest.fixture
def available_area_small():
    """Small available area for testing"""
    return {
        'x': 10,
        'y': 10, 
        'width': 100,
        'height': 50,
        'area': 5000
    }


@pytest.fixture
def available_area_large():
    """Large available area for testing"""
    return {
        'x': 0,
        'y': 0,
        'width': 500,
        'height': 400,
        'area': 200000
    }


@pytest.fixture
def text_positions_no_overlap():
    """Text positions that don't overlap"""
    return [
        {'x': 0, 'y': 0, 'width': 100, 'height': 50},
        {'x': 150, 'y': 0, 'width': 100, 'height': 50},
        {'x': 0, 'y': 100, 'width': 100, 'height': 50}
    ]


@pytest.fixture
def text_positions_with_overlap():
    """Text positions that overlap"""
    return [
        {'x': 0, 'y': 0, 'width': 100, 'height': 50},
        {'x': 50, 'y': 25, 'width': 100, 'height': 50},  # Overlaps first
        {'x': 200, 'y': 0, 'width': 100, 'height': 50}
    ]


@pytest.fixture
def overlays_list():
    """Sample overlays for area calculation"""
    return [
        {'x': 50, 'y': 50, 'width': 100, 'height': 100},
        {'x': 200, 'y': 200, 'width': 80, 'height': 80}
    ]


@pytest.fixture
def mock_props():
    """Mock properties object for generation engine tests"""
    props = Mock()
    props.text = "Test Text"
    props.prepend_text = ""
    props.append_text = ""
    props.background_transparent = False
    props.background_color = (1.0, 1.0, 1.0, 1.0)  # White
    props.text_color = (0.0, 0.0, 0.0, 1.0)  # Black
    props.font_size = 24
    props.font_path = "default"
    props.use_custom_font = False
    props.custom_font_path = ""
    props.enable_text_fitting = False
    props.min_font_size = 8
    props.max_font_size = 200
    props.text_fitting_margin = 10.0
    props.prepend_append_layout = 'HORIZONTAL'
    props.prepend_margin = 10
    props.append_margin = 10
    props.generate_normal_map = False
    props.normal_map_strength = 1.0
    props.normal_map_blur_radius = 0
    props.normal_map_invert = False
    return props
