"""
Page navigation mixin for GLWidget - handles page detection and ghost pages
"""

from typing import TYPE_CHECKING, Optional, Tuple, List

if TYPE_CHECKING:
    from PyQt6.QtWidgets import QMainWindow


class PageNavigationMixin:
    # Type hints for expected attributes from mixing class
    pan_offset: Tuple[float, float]
    zoom_level: float

    def update(self) -> None:  # type: ignore[empty-body]
        """Expected from QWidget"""
        ...

    def window(self) -> "QMainWindow":  # type: ignore[empty-body]
        """Expected from QWidget"""
        ...

    """
    Mixin providing page navigation and ghost page functionality.

    This mixin handles page detection from screen coordinates, calculating
    page positions with ghost pages, and managing ghost page interactions.
    """

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # Current page tracking for operations that need to know which page to work on
        self.current_page_index: int = 0

        # Store page renderers for later use (mouse interaction, text overlays, etc.)
        self._page_renderers: List = []

    def _get_page_at(self, x: float, y: float):
        """
        Get the page at the given screen coordinates.

        Args:
            x: Screen X coordinate
            y: Screen Y coordinate

        Returns:
            Tuple of (page, page_index, renderer) or (None, -1, None) if no page at coordinates
        """
        if not hasattr(self, "_page_renderers") or not self._page_renderers:
            return None, -1, None

        main_window = self.window()
        if not hasattr(main_window, "project") or not main_window.project or not main_window.project.pages:
            return None, -1, None

        # Check each page to find which one contains the coordinates
        for renderer, page in self._page_renderers:
            if renderer.is_point_in_page(x, y):
                # Find the page index in the project's pages list
                page_index = main_window.project.pages.index(page)
                return page, page_index, renderer

        return None, -1, None

    def _get_page_positions(self):
        """
        Calculate page positions including ghost pages.

        Returns:
            List of tuples (page_type, page_or_ghost_data, y_offset)
        """
        # Use stored reference to main window
        main_window = getattr(self, "_main_window", None)
        if main_window is None:
            main_window = self.window()

        try:
            project = main_window.project
            if not project:
                return []
        except (AttributeError, TypeError):
            return []

        dpi = project.working_dpi

        # Use project's page_spacing_mm setting (default is 10mm = 1cm)
        # Convert to pixels at working DPI
        spacing_mm = project.page_spacing_mm
        spacing_px = spacing_mm * dpi / 25.4

        # Start with a small top margin (5mm)
        top_margin_mm = 5.0
        top_margin_px = top_margin_mm * dpi / 25.4

        result = []
        current_y = top_margin_px  # Initial top offset in pixels (not screen pixels)

        # First, render cover if it exists
        for page in project.pages:
            if page.is_cover:
                result.append(("page", page, current_y))

                # Calculate cover height in pixels
                page_height_mm = page.layout.size[1]
                page_height_px = page_height_mm * dpi / 25.4

                # Move to next position (add height + spacing)
                current_y += page_height_px + spacing_px
                break  # Only one cover allowed

        # Get page layout with ghosts from project (this excludes cover)
        layout_with_ghosts = project.calculate_page_layout_with_ghosts()

        for page_type, page_obj, logical_pos in layout_with_ghosts:
            if page_type == "page":
                # Regular page (single or double spread)
                result.append((page_type, page_obj, current_y))

                # Calculate page height in pixels
                # For double spreads, layout.size already contains the doubled width
                page_height_mm = page_obj.layout.size[1]
                page_height_px = page_height_mm * dpi / 25.4

                # Move to next position (add height + spacing)
                current_y += page_height_px + spacing_px

            elif page_type == "ghost":
                # Ghost page - use default page size
                page_size_mm = project.page_size_mm
                from pyPhotoAlbum.models import GhostPageData

                # Create ghost page data with correct size
                ghost = GhostPageData(page_size=page_size_mm)
                result.append((page_type, ghost, current_y))

                # Calculate ghost page height
                page_height_px = page_size_mm[1] * dpi / 25.4

                # Move to next position (add height + spacing)
                current_y += page_height_px + spacing_px

        return result

    def _check_ghost_page_click(self, x: float, y: float) -> bool:
        """
        Check if click is on a ghost page (entire page is clickable) and handle it.

        Args:
            x: Screen X coordinate
            y: Screen Y coordinate

        Returns:
            bool: True if a ghost page was clicked and a new page was created
        """
        if not hasattr(self, "_page_renderers"):
            return False

        main_window = self.window()
        if not hasattr(main_window, "project"):
            return False

        # Get page positions which includes ghosts
        page_positions = self._get_page_positions()

        # Check each position for ghost pages
        for idx, (page_type, page_or_ghost, y_offset) in enumerate(page_positions):
            # Skip non-ghost pages
            if page_type != "ghost":
                continue

            ghost = page_or_ghost
            dpi = main_window.project.working_dpi

            # Calculate ghost page renderer
            ghost_width_mm, ghost_height_mm = ghost.page_size
            screen_x = 50 + self.pan_offset[0]
            screen_y = (y_offset * self.zoom_level) + self.pan_offset[1]

            from pyPhotoAlbum.page_renderer import PageRenderer

            renderer = PageRenderer(
                page_width_mm=ghost_width_mm,
                page_height_mm=ghost_height_mm,
                screen_x=screen_x,
                screen_y=screen_y,
                dpi=dpi,
                zoom=self.zoom_level,
            )

            # Check if click is anywhere on the ghost page (entire page is clickable)
            if renderer.is_point_in_page(x, y):
                # User clicked the ghost page!
                # Calculate the insertion index (count real pages before this ghost in page_positions)
                insert_index = sum(1 for i, (pt, _, _) in enumerate(page_positions) if i < idx and pt == "page")

                print(f"Ghost page clicked at index {insert_index} - inserting new page in place")

                # Create a new page and insert it directly into the pages list
                from pyPhotoAlbum.project import Page
                from pyPhotoAlbum.page_layout import PageLayout

                # Create new page with next page number
                new_page_number = insert_index + 1
                new_page = Page(
                    layout=PageLayout(
                        width=main_window.project.page_size_mm[0], height=main_window.project.page_size_mm[1]
                    ),
                    page_number=new_page_number,
                )

                # Insert the page at the correct position
                main_window.project.pages.insert(insert_index, new_page)

                # Renumber all pages after this one
                for i, page in enumerate(main_window.project.pages):
                    page.page_number = i + 1

                print(f"Inserted page at index {insert_index}, renumbered pages")
                self.update()
                return True

        return False

    def _update_page_status(self, x: float, y: float):
        """
        Update status bar with current page and total page count.

        Args:
            x: Screen X coordinate
            y: Screen Y coordinate
        """
        main_window = self.window()
        if not hasattr(main_window, "project") or not main_window.project or not main_window.project.pages:
            return

        if not hasattr(self, "_page_renderers") or not self._page_renderers:
            return

        # Get total page count (accounting for double spreads = 2 pages each)
        total_pages = sum(page.get_page_count() for page in main_window.project.pages)

        # Find which page mouse is over
        current_page_info = None

        for renderer, page in self._page_renderers:
            # Check if mouse is within this page bounds
            if renderer.is_point_in_page(x, y):
                # For facing page spreads, determine left or right
                if page.is_double_spread:
                    side = renderer.get_sub_page_at(x, is_facing_page=True)
                    page_nums = page.get_page_numbers()
                    if side == "left":
                        current_page_info = f"Page {page_nums[0]}"
                    else:
                        current_page_info = f"Page {page_nums[1]}"
                else:
                    current_page_info = f"Page {page.page_number}"
                break

        # Update status bar
        if hasattr(main_window, "status_bar"):
            if current_page_info:
                main_window.status_bar.showMessage(
                    f"{current_page_info} of {total_pages} | Zoom: {int(self.zoom_level * 100)}%"
                )
            else:
                main_window.status_bar.showMessage(f"Total pages: {total_pages} | Zoom: {int(self.zoom_level * 100)}%")
