#!/usr/bin/env python3
"""
Test script to verify multiselect visual feedback functionality
"""

import pytest
from unittest.mock import Mock, patch, MagicMock
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from pyPhotoAlbum.mixins.element_selection import ElementSelectionMixin
from pyPhotoAlbum.mixins.rendering import RenderingMixin
from pyPhotoAlbum.models import ImageData
from pyPhotoAlbum.project import Project, Page
from pyPhotoAlbum.page_layout import PageLayout


# Create a minimal test widget class that doesn't require full GLWidget initialization
class MultiSelectTestWidget(ElementSelectionMixin, RenderingMixin, QOpenGLWidget):
    """Widget combining necessary mixins for multiselect testing"""

    def __init__(self):
        super().__init__()
        self._page_renderers = []
        self.rotation_mode = False  # Required by _draw_selection_handles


def test_multiselect_visual_feedback(qtbot):
    """Test that all selected elements get selection handles drawn"""

    # Create a project with a page
    project = Project("Test Project")
    page_layout = PageLayout(width=200, height=200)
    page = Page(layout=page_layout, page_number=1)
    project.add_page(page)

    # Create test widget and add to qtbot for proper lifecycle management
    widget = MultiSelectTestWidget()
    qtbot.addWidget(widget)

    # Mock the main window to return our project
    mock_window = Mock()
    mock_window.project = project
    widget.window = Mock(return_value=mock_window)

    # Create test elements
    element1 = ImageData(image_path="test1.jpg", x=10, y=10, width=50, height=50)
    element2 = ImageData(image_path="test2.jpg", x=70, y=70, width=50, height=50)
    element3 = ImageData(image_path="test3.jpg", x=130, y=130, width=50, height=50)

    # Set up page renderer mock for each element
    mock_renderer = Mock()
    mock_renderer.page_to_screen = Mock(side_effect=lambda x, y: (x, y))
    mock_renderer.zoom = 1.0

    element1._parent_page = page
    element2._parent_page = page
    element3._parent_page = page

    element1._page_renderer = mock_renderer
    element2._page_renderer = mock_renderer
    element3._page_renderer = mock_renderer

    # Add elements to page
    page.layout.add_element(element1)
    page.layout.add_element(element2)
    page.layout.add_element(element3)

    print(f"Created 3 test elements")

    # Test 1: Single selection
    print("\nTest 1: Single selection")
    widget.selected_elements = {element1}

    with patch.object(widget, "_draw_selection_handles") as mock_draw:
        # Simulate paintGL call (only the relevant part)
        for selected_elem in widget.selected_elements:
            widget._draw_selection_handles(selected_elem)

        assert mock_draw.call_count == 1, f"Expected 1 call, got {mock_draw.call_count}"
        assert mock_draw.call_args[0][0] == element1, "Wrong element passed"
        print(f"✓ Single selection: _draw_selection_handles called 1 time with element1")

    # Test 2: Multiple selection (2 elements)
    print("\nTest 2: Multiple selection (2 elements)")
    widget.selected_elements = {element1, element2}

    with patch.object(widget, "_draw_selection_handles") as mock_draw:
        for selected_elem in widget.selected_elements:
            widget._draw_selection_handles(selected_elem)

        assert mock_draw.call_count == 2, f"Expected 2 calls, got {mock_draw.call_count}"
        called_elements = {call[0][0] for call in mock_draw.call_args_list}
        assert called_elements == {element1, element2}, f"Wrong elements passed: {called_elements}"
        print(f"✓ Multiple selection (2): _draw_selection_handles called 2 times with correct elements")

    # Test 3: Multiple selection (3 elements)
    print("\nTest 3: Multiple selection (3 elements)")
    widget.selected_elements = {element1, element2, element3}

    with patch.object(widget, "_draw_selection_handles") as mock_draw:
        for selected_elem in widget.selected_elements:
            widget._draw_selection_handles(selected_elem)

        assert mock_draw.call_count == 3, f"Expected 3 calls, got {mock_draw.call_count}"
        called_elements = {call[0][0] for call in mock_draw.call_args_list}
        assert called_elements == {element1, element2, element3}, f"Wrong elements passed: {called_elements}"
        print(f"✓ Multiple selection (3): _draw_selection_handles called 3 times with correct elements")

    # Test 4: No selection
    print("\nTest 4: No selection")
    widget.selected_elements = set()

    with patch.object(widget, "_draw_selection_handles") as mock_draw:
        for selected_elem in widget.selected_elements:
            widget._draw_selection_handles(selected_elem)

        assert mock_draw.call_count == 0, f"Expected 0 calls, got {mock_draw.call_count}"
        print(f"✓ No selection: _draw_selection_handles not called")

    # Test 5: Verify _draw_selection_handles receives correct element parameter
    print("\nTest 5: Verify _draw_selection_handles uses passed element")
    widget.selected_elements = {element2}

    # Mock OpenGL functions
    with (
        patch("pyPhotoAlbum.gl_widget.glColor3f"),
        patch("pyPhotoAlbum.gl_widget.glLineWidth"),
        patch("pyPhotoAlbum.gl_widget.glBegin"),
        patch("pyPhotoAlbum.gl_widget.glEnd"),
        patch("pyPhotoAlbum.gl_widget.glVertex2f"),
        patch("pyPhotoAlbum.gl_widget.glPushMatrix"),
        patch("pyPhotoAlbum.gl_widget.glPopMatrix"),
        patch("pyPhotoAlbum.gl_widget.glTranslatef"),
        patch("pyPhotoAlbum.gl_widget.glRotatef"),
    ):

        # Call the actual method
        widget._draw_selection_handles(element2)

        # Verify it used element2's properties
        assert element2._page_renderer.page_to_screen.called, "page_to_screen should be called"
        print(f"✓ _draw_selection_handles correctly uses the passed element parameter")

    print("\n✓ All multiselect visual feedback tests passed!")


def test_regression_old_code_bug(qtbot):
    """
    Regression test: Verify the old bug (only first element gets handles)
    would have been caught by this test
    """
    print("\nRegression test: Simulating old buggy behavior...")

    widget = MultiSelectTestWidget()
    qtbot.addWidget(widget)

    # Create mock elements
    element1 = Mock()
    element2 = Mock()
    element3 = Mock()

    # Select multiple elements
    widget.selected_elements = {element1, element2, element3}

    # OLD BUGGY CODE (what we fixed):
    # if self.selected_element:  # This only returns first element!
    #     self._draw_selection_handles()

    # Simulate old behavior
    call_count_old = 0
    if widget.selected_element:  # This property returns only first element
        call_count_old = 1

    # NEW CORRECT CODE:
    # for selected_elem in self.selected_elements:
    #     self._draw_selection_handles(selected_elem)

    # Simulate new behavior
    call_count_new = 0
    for selected_elem in widget.selected_elements:
        call_count_new += 1

    print(f"Old buggy code: would call _draw_selection_handles {call_count_old} time(s)")
    print(f"New fixed code: calls _draw_selection_handles {call_count_new} time(s)")

    assert call_count_old == 1, "Old code should only handle 1 element"
    assert call_count_new == 3, "New code should handle all 3 elements"

    print("✓ Regression test confirms the bug would have been caught!")
