"""
Tests for PageNavigationMixin
"""

import pytest
from unittest.mock import Mock, MagicMock, patch
from PyQt6.QtOpenGLWidgets import QOpenGLWidget
from pyPhotoAlbum.mixins.page_navigation import PageNavigationMixin
from pyPhotoAlbum.mixins.viewport import ViewportMixin
from pyPhotoAlbum.project import Project, Page
from pyPhotoAlbum.page_layout import PageLayout
from pyPhotoAlbum.models import GhostPageData


# Create test widget combining necessary mixins
class TestPageNavWidget(PageNavigationMixin, ViewportMixin, QOpenGLWidget):
    """Test widget combining page navigation and viewport mixins"""

    pass


class TestPageNavigationInitialization:
    """Test PageNavigationMixin initialization"""

    def test_initialization_sets_defaults(self, qtbot):
        """Test that mixin initializes with correct defaults"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        assert widget.current_page_index == 0
        assert widget._page_renderers == []

    def test_current_page_index_is_mutable(self, qtbot):
        """Test that current page index can be changed"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        widget.current_page_index = 5
        assert widget.current_page_index == 5


class TestGetPageAt:
    """Test _get_page_at method"""

    def test_get_page_at_no_renderers(self, qtbot):
        """Test returns None when no renderers"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        result = widget._get_page_at(100, 100)
        assert result == (None, -1, None)

    def test_get_page_at_no_project(self, qtbot):
        """Test returns None when no project"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        # Set up renderers but no project
        mock_renderer = Mock()
        widget._page_renderers = [(mock_renderer, Mock())]

        mock_window = Mock()
        mock_window.project = None
        widget.window = Mock(return_value=mock_window)

        result = widget._get_page_at(100, 100)
        assert result == (None, -1, None)

    def test_get_page_at_finds_page(self, qtbot):
        """Test finds page at coordinates"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        # Create project with page
        mock_window = Mock()
        mock_window.project = Project(name="Test")
        page = Page(layout=PageLayout(width=210, height=297), page_number=1)
        mock_window.project.pages = [page]

        # Create renderer that returns True for is_point_in_page
        mock_renderer = Mock()
        mock_renderer.is_point_in_page = Mock(return_value=True)

        widget._page_renderers = [(mock_renderer, page)]
        widget.window = Mock(return_value=mock_window)

        result_page, result_index, result_renderer = widget._get_page_at(100, 100)

        assert result_page is page
        assert result_index == 0
        assert result_renderer is mock_renderer

    def test_get_page_at_multiple_pages(self, qtbot):
        """Test finds correct page when multiple pages exist"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        mock_window = Mock()
        mock_window.project = Project(name="Test")
        page1 = Page(layout=PageLayout(width=210, height=297), page_number=1)
        page2 = Page(layout=PageLayout(width=210, height=297), page_number=2)
        page3 = Page(layout=PageLayout(width=210, height=297), page_number=3)
        mock_window.project.pages = [page1, page2, page3]

        # First renderer returns False, second returns True
        renderer1 = Mock()
        renderer1.is_point_in_page = Mock(return_value=False)
        renderer2 = Mock()
        renderer2.is_point_in_page = Mock(return_value=True)
        renderer3 = Mock()
        renderer3.is_point_in_page = Mock(return_value=False)

        widget._page_renderers = [(renderer1, page1), (renderer2, page2), (renderer3, page3)]
        widget.window = Mock(return_value=mock_window)

        result_page, result_index, result_renderer = widget._get_page_at(100, 100)

        assert result_page is page2
        assert result_index == 1
        assert result_renderer is renderer2


class TestGetPagePositions:
    """Test _get_page_positions method"""

    def test_get_page_positions_no_project(self, qtbot):
        """Test returns empty list when no project"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        mock_window = Mock()
        del mock_window.project  # No project attribute
        widget.window = Mock(return_value=mock_window)

        result = widget._get_page_positions()
        assert result == []

    def test_get_page_positions_single_page(self, qtbot):
        """Test calculates positions for single page"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        mock_window = Mock()
        mock_window.project = Project(name="Test")
        mock_window.project.working_dpi = 96
        mock_window.project.page_spacing_mm = 10
        mock_window.project.page_size_mm = (210, 297)

        page = Page(layout=PageLayout(width=210, height=297), page_number=1)
        mock_window.project.pages = [page]

        # Mock calculate_page_layout_with_ghosts
        mock_window.project.calculate_page_layout_with_ghosts = Mock(return_value=[("page", page, 0)])

        widget.window = Mock(return_value=mock_window)

        result = widget._get_page_positions()

        # Should have one page entry
        assert len(result) >= 1
        assert result[0][0] == "page"
        assert result[0][1] is page

    def test_get_page_positions_includes_ghosts(self, qtbot):
        """Test includes ghost pages in result"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        mock_window = Mock()
        mock_window.project = Project(name="Test")
        mock_window.project.working_dpi = 96
        mock_window.project.page_spacing_mm = 10
        mock_window.project.page_size_mm = (210, 297)

        page = Page(layout=PageLayout(width=210, height=297), page_number=1)
        mock_window.project.pages = [page]

        # Mock with ghost page
        mock_window.project.calculate_page_layout_with_ghosts = Mock(
            return_value=[("page", page, 0), ("ghost", None, 1)]
        )

        widget.window = Mock(return_value=mock_window)

        result = widget._get_page_positions()

        # Should have page + ghost
        assert len(result) >= 2
        page_types = [r[0] for r in result]
        assert "page" in page_types
        assert "ghost" in page_types


class TestCheckGhostPageClick:
    """Test _check_ghost_page_click method"""

    def test_check_ghost_page_no_renderers(self, qtbot):
        """Test returns False when no renderers"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        result = widget._check_ghost_page_click(100, 100)
        assert result is False

    def test_check_ghost_page_no_project(self, qtbot):
        """Test returns False when no project"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        widget._page_renderers = []
        mock_window = Mock()
        del mock_window.project
        widget.window = Mock(return_value=mock_window)

        result = widget._check_ghost_page_click(100, 100)
        assert result is False

    @patch("pyPhotoAlbum.page_renderer.PageRenderer")
    def test_check_ghost_page_click_on_ghost(self, mock_page_renderer_class, qtbot):
        """Test clicking on ghost page creates new page"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)
        widget.zoom_level = 1.0
        widget.pan_offset = [0, 0]

        # Mock the update method
        widget.update = Mock()

        # Setup project
        mock_window = Mock()
        mock_window.project = Project(name="Test")
        mock_window.project.working_dpi = 96
        mock_window.project.page_spacing_mm = 10
        mock_window.project.page_size_mm = (210, 297)
        mock_window.project.pages = []

        # Mock _get_page_positions to return a ghost
        ghost = GhostPageData(page_size=(210, 297))
        widget._get_page_positions = Mock(return_value=[("ghost", ghost, 100)])

        # Mock PageRenderer to say click is in page
        mock_renderer_instance = Mock()
        mock_renderer_instance.is_point_in_page = Mock(return_value=True)
        mock_page_renderer_class.return_value = mock_renderer_instance

        widget.window = Mock(return_value=mock_window)

        # Click on ghost page
        result = widget._check_ghost_page_click(150, 150)

        # Should return True and create page
        assert result is True
        assert len(mock_window.project.pages) == 1
        assert widget.update.called

    @patch("pyPhotoAlbum.page_renderer.PageRenderer")
    def test_check_ghost_page_click_outside_ghost(self, mock_page_renderer_class, qtbot):
        """Test clicking outside ghost page returns False"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)
        widget.zoom_level = 1.0
        widget.pan_offset = [0, 0]

        mock_window = Mock()
        mock_window.project = Project(name="Test")
        mock_window.project.working_dpi = 96
        mock_window.project.page_spacing_mm = 10
        mock_window.project.page_size_mm = (210, 297)
        mock_window.project.pages = []

        ghost = GhostPageData(page_size=(210, 297))
        widget._get_page_positions = Mock(return_value=[("ghost", ghost, 100)])

        # Mock renderer to say click is NOT in page
        mock_renderer_instance = Mock()
        mock_renderer_instance.is_point_in_page = Mock(return_value=False)
        mock_page_renderer_class.return_value = mock_renderer_instance

        widget.window = Mock(return_value=mock_window)

        result = widget._check_ghost_page_click(5000, 5000)

        assert result is False
        assert len(mock_window.project.pages) == 0


class TestUpdatePageStatus:
    """Test _update_page_status method"""

    def test_update_page_status_no_project(self, qtbot):
        """Test does nothing when no project"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        mock_window = Mock()
        mock_window.project = None
        widget.window = Mock(return_value=mock_window)

        # Should not raise exception
        widget._update_page_status(100, 100)

    def test_update_page_status_no_renderers(self, qtbot):
        """Test does nothing when no renderers"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)

        mock_window = Mock()
        mock_window.project = Project(name="Test")
        mock_window.project.pages = []
        widget.window = Mock(return_value=mock_window)

        widget._update_page_status(100, 100)

    def test_update_page_status_on_page(self, qtbot):
        """Test updates status bar when on a page"""
        widget = TestPageNavWidget()
        qtbot.addWidget(widget)
        widget.zoom_level = 1.0

        mock_window = Mock()
        mock_window.project = Project(name="Test")
        page = Page(layout=PageLayout(width=210, height=297), page_number=1)
        page.get_page_count = Mock(return_value=1)
        page.is_double_spread = False
        mock_window.project.pages = [page]
        mock_window.status_bar = Mock()

        mock_renderer = Mock()
        mock_renderer.is_point_in_page = Mock(return_value=True)

        widget._page_renderers = [(mock_renderer, page)]
        widget.window = Mock(return_value=mock_window)

        widget._update_page_status(100, 100)

        # Status bar should be updated
        assert mock_window.status_bar.showMessage.called
        call_args = mock_window.status_bar.showMessage.call_args[0][0]
        assert "Page 1" in call_args
