"""Type stubs for the oxidize-pdf native extension module."""

from typing import Optional

# ── Module metadata ────────────────────────────────────────────────────────────

__version__: str

# ── Exceptions ─────────────────────────────────────────────────────────────────

class PdfError(Exception):
    """Base exception for all oxidize-pdf errors."""
    ...

class PdfParseError(PdfError):
    """Raised when PDF parsing fails."""
    ...

class PdfIoError(PdfError):
    """Raised on I/O errors (file not found, permission denied, etc.)."""
    ...

class PdfEncryptionError(PdfError):
    """Raised on encryption/decryption errors."""
    ...

class PdfPermissionError(PdfError):
    """Raised when an operation is denied by document permissions."""
    ...

# ── Color ──────────────────────────────────────────────────────────────────────

class Color:
    """A color value in RGB, Gray, or CMYK color space."""

    @staticmethod
    def rgb(r: float, g: float, b: float) -> Color: ...
    @staticmethod
    def gray(value: float) -> Color: ...
    @staticmethod
    def cmyk(c: float, m: float, y: float, k: float) -> Color: ...
    @staticmethod
    def hex(hex_str: str) -> Color: ...
    @staticmethod
    def black() -> Color: ...
    @staticmethod
    def white() -> Color: ...
    @staticmethod
    def red() -> Color: ...
    @staticmethod
    def green() -> Color: ...
    @staticmethod
    def blue() -> Color: ...

    @property
    def r(self) -> float: ...
    @property
    def g(self) -> float: ...
    @property
    def b(self) -> float: ...
    @property
    def gray_value(self) -> float: ...
    @property
    def c(self) -> float: ...
    @property
    def m(self) -> float: ...
    @property
    def y(self) -> float: ...
    @property
    def k(self) -> float: ...
    @property
    def color_space(self) -> str: ...

    def __repr__(self) -> str: ...

# ── Point ──────────────────────────────────────────────────────────────────────

class Point:
    """A 2D point with x and y coordinates."""

    def __init__(self, x: float, y: float) -> None: ...

    @staticmethod
    def origin() -> Point: ...

    @property
    def x(self) -> float: ...
    @property
    def y(self) -> float: ...

    def __repr__(self) -> str: ...
    def __eq__(self, other: object) -> bool: ...

# ── Rectangle ──────────────────────────────────────────────────────────────────

class Rectangle:
    """An axis-aligned rectangle defined by two corner points."""

    def __init__(self, lower_left: Point, upper_right: Point) -> None: ...

    @staticmethod
    def from_xywh(x: float, y: float, width: float, height: float) -> Rectangle: ...

    @property
    def lower_left(self) -> Point: ...
    @property
    def upper_right(self) -> Point: ...
    @property
    def width(self) -> float: ...
    @property
    def height(self) -> float: ...
    @property
    def center(self) -> Point: ...

    def __repr__(self) -> str: ...

# ── Margins ────────────────────────────────────────────────────────────────────

class Margins:
    """Page margins (top, right, bottom, left) in points."""

    def __init__(
        self,
        top: float = 0.0,
        right: float = 0.0,
        bottom: float = 0.0,
        left: float = 0.0,
    ) -> None: ...

    @staticmethod
    def uniform(value: float) -> Margins: ...

    @property
    def top(self) -> float: ...
    @property
    def right(self) -> float: ...
    @property
    def bottom(self) -> float: ...
    @property
    def left(self) -> float: ...

    def __repr__(self) -> str: ...

# ── Font ───────────────────────────────────────────────────────────────────────

class Font:
    """Standard PDF fonts. Access as class attributes: ``Font.HELVETICA``, etc."""

    HELVETICA: Font
    HELVETICA_BOLD: Font
    HELVETICA_OBLIQUE: Font
    HELVETICA_BOLD_OBLIQUE: Font
    TIMES_ROMAN: Font
    TIMES_BOLD: Font
    TIMES_ITALIC: Font
    TIMES_BOLD_ITALIC: Font
    COURIER: Font
    COURIER_BOLD: Font
    COURIER_OBLIQUE: Font
    COURIER_BOLD_OBLIQUE: Font
    SYMBOL: Font
    ZAPF_DINGBATS: Font

    def __repr__(self) -> str: ...

# ── TextAlign ──────────────────────────────────────────────────────────────────

class TextAlign:
    """Text alignment options."""

    LEFT: TextAlign
    RIGHT: TextAlign
    CENTER: TextAlign
    JUSTIFIED: TextAlign

    def __repr__(self) -> str: ...

# ── Page ───────────────────────────────────────────────────────────────────────

class Page:
    """A page in a PDF document for adding text and graphics content."""

    def __init__(self, width: float, height: float) -> None: ...

    @staticmethod
    def a4() -> Page: ...
    @staticmethod
    def a4_landscape() -> Page: ...
    @staticmethod
    def letter() -> Page: ...
    @staticmethod
    def letter_landscape() -> Page: ...
    @staticmethod
    def legal() -> Page: ...
    @staticmethod
    def legal_landscape() -> Page: ...

    @property
    def width(self) -> float: ...
    @property
    def height(self) -> float: ...
    @property
    def margins(self) -> Margins: ...

    def set_margins(self, margins: Margins) -> None: ...

    # Text operations
    def set_font(self, font: Font, size: float) -> None: ...
    def set_text_color(self, color: Color) -> None: ...
    def set_character_spacing(self, spacing: float) -> None: ...
    def set_word_spacing(self, spacing: float) -> None: ...
    def set_leading(self, leading: float) -> None: ...
    def text_at(self, x: float, y: float, text: str) -> None: ...

    # Graphics operations
    def set_fill_color(self, color: Color) -> None: ...
    def set_stroke_color(self, color: Color) -> None: ...
    def set_line_width(self, width: float) -> None: ...
    def set_fill_opacity(self, opacity: float) -> None: ...
    def set_stroke_opacity(self, opacity: float) -> None: ...
    def draw_rect(self, x: float, y: float, width: float, height: float) -> None: ...
    def draw_circle(self, cx: float, cy: float, radius: float) -> None: ...
    def move_to(self, x: float, y: float) -> None: ...
    def line_to(self, x: float, y: float) -> None: ...
    def curve_to(
        self, x1: float, y1: float, x2: float, y2: float, x3: float, y3: float
    ) -> None: ...
    def close_path(self) -> None: ...
    def fill(self) -> None: ...
    def stroke(self) -> None: ...
    def fill_and_stroke(self) -> None: ...

    def __repr__(self) -> str: ...

# ── Document ───────────────────────────────────────────────────────────────────

class Document:
    """A PDF document that can contain multiple pages and metadata."""

    def __init__(self) -> None: ...

    @property
    def page_count(self) -> int: ...
    @property
    def is_encrypted(self) -> bool: ...

    def set_title(self, title: str) -> None: ...
    def set_author(self, author: str) -> None: ...
    def set_subject(self, subject: str) -> None: ...
    def set_keywords(self, keywords: str) -> None: ...
    def set_creator(self, creator: str) -> None: ...
    def add_page(self, page: Page) -> None: ...
    def save(self, path: str) -> None: ...
    def save_to_bytes(self) -> bytes: ...
    def encrypt(
        self,
        user_password: str,
        owner_password: str,
        permissions: Optional[Permissions] = None,
    ) -> None: ...

    def __repr__(self) -> str: ...

# ── PdfReader ──────────────────────────────────────────────────────────────────

class PdfReader:
    """High-level PDF reader for parsing existing PDF files."""

    @staticmethod
    def open(path: str) -> PdfReader: ...

    @property
    def is_encrypted(self) -> bool: ...
    @property
    def page_count(self) -> int: ...
    @property
    def version(self) -> str: ...

    def unlock(self, password: str) -> None: ...
    def get_page(self, index: int) -> ParsedPage: ...
    def extract_text_from_page(self, index: int) -> str: ...
    def extract_text(self) -> list[str]: ...

    def __len__(self) -> int: ...
    def __repr__(self) -> str: ...

# ── ParsedPage ─────────────────────────────────────────────────────────────────

class ParsedPage:
    """A page obtained from parsing an existing PDF."""

    @property
    def width(self) -> float: ...
    @property
    def height(self) -> float: ...
    @property
    def rotation(self) -> int: ...

    def __repr__(self) -> str: ...

# ── Permissions ────────────────────────────────────────────────────────────────

class Permissions:
    """PDF document permissions for encrypted documents."""

    def __init__(
        self,
        print: bool = False,
        copy: bool = False,
        modify_contents: bool = False,
        modify_annotations: bool = False,
        fill_forms: bool = False,
        accessibility: bool = True,
        assemble: bool = False,
        print_high_quality: bool = False,
    ) -> None: ...

    @staticmethod
    def all() -> Permissions: ...
    @staticmethod
    def none() -> Permissions: ...

    @property
    def can_print(self) -> bool: ...
    @property
    def can_copy(self) -> bool: ...
    @property
    def can_modify_contents(self) -> bool: ...
    @property
    def can_modify_annotations(self) -> bool: ...
    @property
    def can_fill_forms(self) -> bool: ...
    @property
    def can_assemble(self) -> bool: ...
    @property
    def can_print_high_quality(self) -> bool: ...

    def __repr__(self) -> str: ...

# ── Operations ─────────────────────────────────────────────────────────────────

def split_pdf(input_path: str, output_dir: str) -> list[str]:
    """Split a PDF into individual single-page files.

    Args:
        input_path: Path to the input PDF file.
        output_dir: Directory where split pages will be written.

    Returns:
        A list of paths to the created files.

    Raises:
        PdfError: If the input file cannot be read or split.
        PdfIoError: If there is an I/O error.
    """
    ...

def merge_pdfs(input_paths: list[str], output_path: str) -> None:
    """Merge multiple PDF files into a single output file.

    Args:
        input_paths: List of paths to PDF files to merge (in order).
        output_path: Path where the merged PDF will be written.

    Raises:
        PdfError: If any input file cannot be read or the merge fails.
        PdfIoError: If there is an I/O error.
        ValueError: If the input list is empty.
    """
    ...

def rotate_pdf(input_path: str, output_path: str, degrees: int) -> None:
    """Rotate all pages of a PDF by the given angle.

    Args:
        input_path: Path to the input PDF file.
        output_path: Path where the rotated PDF will be written.
        degrees: Rotation angle in degrees. Must be 0, 90, 180, or 270.

    Raises:
        PdfError: If the rotation angle is invalid or the file cannot be processed.
        PdfIoError: If there is an I/O error.
    """
    ...

def extract_pages(input_path: str, output_path: str, page_indices: list[int]) -> None:
    """Extract specific pages from a PDF into a new file.

    Args:
        input_path: Path to the input PDF file.
        output_path: Path where the extracted pages will be written.
        page_indices: List of 0-based page indices to extract.

    Raises:
        PdfError: If a page index is out of bounds or the file cannot be processed.
        PdfIoError: If there is an I/O error.
        ValueError: If the page list is empty.
    """
    ...
