"""
Page renderer helper for pyPhotoAlbum

This module provides a unified coordinate system for rendering pages and their elements.
All coordinate transformations are centralized here to ensure consistency.

Coordinate Systems:
- Page-local: Coordinates in millimeters relative to the page's top-left corner
- Pixel: Coordinates in pixels at working DPI
- Screen: Coordinates on screen after applying zoom and pan
"""

from typing import Tuple, Optional
from pyPhotoAlbum.gl_imports import glPushMatrix, glPopMatrix, glScalef, glTranslatef


class PageRenderer:
    """
    Handles rendering and coordinate transformations for a single page.

    This class encapsulates all coordinate transformations needed to render
    a page and its elements consistently.
    """

    def __init__(
        self, page_width_mm: float, page_height_mm: float, screen_x: float, screen_y: float, dpi: int, zoom: float
    ):
        """
        Initialize a page renderer.

        Args:
            page_width_mm: Page width in millimeters
            page_height_mm: Page height in millimeters
            screen_x: X position on screen where page should be rendered
            screen_y: Y position on screen where page should be rendered
            dpi: Working DPI for converting mm to pixels
            zoom: Current zoom level
        """
        self.page_width_mm = page_width_mm
        self.page_height_mm = page_height_mm
        self.screen_x = screen_x
        self.screen_y = screen_y
        self.dpi = dpi
        self.zoom = zoom

        # Calculate page dimensions in pixels
        self.page_width_px = page_width_mm * dpi / 25.4
        self.page_height_px = page_height_mm * dpi / 25.4

        # Calculate screen dimensions (with zoom applied)
        self.screen_width = self.page_width_px * zoom
        self.screen_height = self.page_height_px * zoom

    def page_to_screen(self, page_x: float, page_y: float) -> Tuple[float, float]:
        """
        Convert page-local coordinates (in pixels) to screen coordinates.

        Args:
            page_x: X coordinate in page-local space (pixels)
            page_y: Y coordinate in page-local space (pixels)

        Returns:
            Tuple of (screen_x, screen_y)
        """
        screen_x = self.screen_x + page_x * self.zoom
        screen_y = self.screen_y + page_y * self.zoom
        return (screen_x, screen_y)

    def screen_to_page(self, screen_x: float, screen_y: float) -> Tuple[float, float]:
        """
        Convert screen coordinates to page-local coordinates (in pixels).

        Args:
            screen_x: X coordinate in screen space
            screen_y: Y coordinate in screen space

        Returns:
            Tuple of (page_x, page_y) in pixels, or None if outside page bounds
        """
        page_x = (screen_x - self.screen_x) / self.zoom
        page_y = (screen_y - self.screen_y) / self.zoom
        return (page_x, page_y)

    def is_point_in_page(self, screen_x: float, screen_y: float) -> bool:
        """
        Check if a screen coordinate is within the page bounds.

        Args:
            screen_x: X coordinate in screen space
            screen_y: Y coordinate in screen space

        Returns:
            True if the point is within the page bounds
        """
        return (
            self.screen_x <= screen_x <= self.screen_x + self.screen_width
            and self.screen_y <= screen_y <= self.screen_y + self.screen_height
        )

    def get_sub_page_at(self, screen_x: float, is_facing_page: bool) -> Optional[str]:
        """
        For facing page spreads, determine if mouse is on left or right page.

        Args:
            screen_x: X coordinate in screen space
            is_facing_page: Whether this is a facing page spread

        Returns:
            'left' or 'right' for facing pages, None for single pages
        """
        if not is_facing_page:
            return None

        # Calculate the center line of the spread
        center_x = self.screen_x + self.screen_width / 2

        if screen_x < center_x:
            return "left"
        else:
            return "right"

    def begin_render(self):
        """
        Set up OpenGL transformations for rendering this page.
        Call this before rendering page content.
        """
        glPushMatrix()
        # Apply zoom
        glScalef(self.zoom, self.zoom, 1.0)
        # Translate to page position (in zoomed coordinates)
        glTranslatef(self.screen_x / self.zoom, self.screen_y / self.zoom, 0.0)

    def end_render(self):
        """
        Clean up OpenGL transformations after rendering this page.
        Call this after rendering page content.
        """
        glPopMatrix()

    def get_page_bounds_screen(self) -> Tuple[float, float, float, float]:
        """
        Get the page bounds in screen coordinates.

        Returns:
            Tuple of (x, y, width, height) in screen space
        """
        return (self.screen_x, self.screen_y, self.screen_width, self.screen_height)

    def get_page_bounds_page(self) -> Tuple[float, float, float, float]:
        """
        Get the page bounds in page-local coordinates.

        Returns:
            Tuple of (x, y, width, height) in page-local space (pixels)
        """
        return (0, 0, self.page_width_px, self.page_height_px)
