"""
Keyboard navigation mixin for GLWidget - handles keyboard-based navigation
"""

from PyQt6.QtCore import Qt


class KeyboardNavigationMixin:
    """
    Mixin providing keyboard navigation functionality.

    This mixin handles Page Up/Down navigation between pages,
    arrow key viewport movement, and arrow key element movement.
    """

    def _navigate_to_next_page(self):
        """Navigate to the next page using Page Down key"""
        main_window = self.window()
        if not hasattr(main_window, "project") or not main_window.project or not main_window.project.pages:
            return

        current_index = main_window._get_most_visible_page_index()
        if current_index < len(main_window.project.pages) - 1:
            next_page = main_window.project.pages[current_index + 1]
            self._scroll_to_page(next_page, current_index + 1)

            if hasattr(main_window, "show_status"):
                page_name = main_window.project.get_page_display_name(next_page)
                main_window.show_status(f"Navigated to {page_name}", 2000)

    def _navigate_to_previous_page(self):
        """Navigate to the previous page using Page Up key"""
        main_window = self.window()
        if not hasattr(main_window, "project") or not main_window.project or not main_window.project.pages:
            return

        current_index = main_window._get_most_visible_page_index()
        if current_index > 0:
            prev_page = main_window.project.pages[current_index - 1]
            self._scroll_to_page(prev_page, current_index - 1)

            if hasattr(main_window, "show_status"):
                page_name = main_window.project.get_page_display_name(prev_page)
                main_window.show_status(f"Navigated to {page_name}", 2000)

    def _scroll_to_page(self, page, page_index):
        """
        Scroll the viewport to center a specific page.

        Args:
            page: The page to scroll to
            page_index: The index of the page in the project
        """
        main_window = self.window()
        if not hasattr(main_window, "project"):
            return

        dpi = main_window.project.working_dpi
        PAGE_MARGIN = 50
        PAGE_SPACING = 50

        # Calculate the Y offset for this page
        y_offset = PAGE_MARGIN
        for i in range(page_index):
            prev_page = main_window.project.pages[i]
            prev_height_mm = prev_page.layout.size[1]
            prev_height_px = prev_height_mm * dpi / 25.4
            y_offset += prev_height_px * self.zoom_level + PAGE_SPACING

        # Get page height
        page_height_mm = page.layout.size[1]
        page_height_px = page_height_mm * dpi / 25.4
        screen_page_height = page_height_px * self.zoom_level

        # Center the page in the viewport
        viewport_height = self.height()
        target_pan_y = viewport_height / 2 - y_offset - screen_page_height / 2

        self.pan_offset[1] = target_pan_y

        # Clamp pan offset to content bounds
        if hasattr(self, "clamp_pan_offset"):
            self.clamp_pan_offset()

        self.update()

        # Update scrollbars if available
        main_window = self.window()
        if hasattr(main_window, "update_scrollbars"):
            main_window.update_scrollbars()

    def _move_viewport_with_arrow_keys(self, key):
        """
        Move the viewport using arrow keys when no objects are selected.

        Args:
            key: The Qt key code (Up, Down, Left, Right)
        """
        # Movement amount in pixels
        move_amount = 50

        if key == Qt.Key.Key_Up:
            self.pan_offset[1] += move_amount
        elif key == Qt.Key.Key_Down:
            self.pan_offset[1] -= move_amount
        elif key == Qt.Key.Key_Left:
            self.pan_offset[0] += move_amount
        elif key == Qt.Key.Key_Right:
            self.pan_offset[0] -= move_amount

        # Clamp pan offset to content bounds
        if hasattr(self, "clamp_pan_offset"):
            self.clamp_pan_offset()

        self.update()

        # Update scrollbars if available
        main_window = self.window()
        if hasattr(main_window, "update_scrollbars"):
            main_window.update_scrollbars()

    def _move_selected_elements_with_arrow_keys(self, key):
        """
        Move selected elements using arrow keys.

        Args:
            key: The Qt key code (Up, Down, Left, Right)
        """
        main_window = self.window()
        if not hasattr(main_window, "project"):
            return

        # Movement amount in mm
        move_amount_mm = 1.0  # 1mm per keypress

        # Calculate movement delta
        dx, dy = 0, 0
        if key == Qt.Key.Key_Up:
            dy = -move_amount_mm
        elif key == Qt.Key.Key_Down:
            dy = move_amount_mm
        elif key == Qt.Key.Key_Left:
            dx = -move_amount_mm
        elif key == Qt.Key.Key_Right:
            dx = move_amount_mm

        # Move all selected elements
        for element in self.selected_elements:
            current_x, current_y = element.position
            new_x = current_x + dx
            new_y = current_y + dy

            # Apply snapping if element has a parent page
            if hasattr(element, "_parent_page") and element._parent_page:
                page = element._parent_page
                snap_sys = page.layout.snapping_system
                page_size = page.layout.size
                dpi = main_window.project.working_dpi

                snapped_pos = snap_sys.snap_position(
                    position=(new_x, new_y),
                    size=element.size,
                    page_size=page_size,
                    dpi=dpi,
                    project=main_window.project,
                )
                element.position = snapped_pos
            else:
                element.position = (new_x, new_y)

        self.update()

        if hasattr(main_window, "show_status"):
            count = len(self.selected_elements)
            elem_text = "element" if count == 1 else "elements"
            main_window.show_status(f"Moved {count} {elem_text}", 1000)
