from collections.abc import Callable
from typing import IO, NamedTuple, Self
from xml.etree.ElementTree import Element, ElementTree
import re

from .image import Image, SvgImageFile

class WillowSvgException(Exception): ...
class InvalidSvgAttribute(WillowSvgException): ...
class InvalidSvgSizeAttribute(WillowSvgException): ...
class SvgViewBoxParseError(WillowSvgException): ...

class ViewBox(NamedTuple):
    min_x: float
    min_y: float
    width: float
    height: float

def view_box_to_attr_str(view_box: ViewBox) -> str: ...

class ViewportToUserSpaceTransform:
    scale_x: float
    scale_y: float
    translate_x: float
    translate_y: float
    def __init__(
        self,
        scale_x: float,
        scale_y: float,
        translate_x: float,
        translate_y: float,
    ) -> None: ...
    def __eq__(self, other: object) -> bool: ...
    def __call__(self, rect: tuple[float, float, float, float]) -> tuple[float, float, float, float]: ...

def get_viewport_to_user_space_transform(
    svg: SvgImage,
) -> ViewportToUserSpaceTransform: ...

class SvgWrapper:
    UNIT_RE: re.Pattern[str]
    NUMBER_PATTERN: str
    VIEW_BOX_RE: re.Pattern[str]
    PRESERVE_ASPECT_RATIO_RE: re.Pattern[str]
    COEFFICIENTS: dict[str, float]
    dom: ElementTree
    dpi: int
    font_size_px: int
    view_box: ViewBox
    preserve_aspect_ratio: str
    width: float
    height: float
    def __init__(self, dom: ElementTree, dpi: int = 96, font_size_px: int = 16) -> None: ...
    def __copy__(self) -> Self: ...
    @classmethod
    def from_file(cls, f: IO[bytes]) -> Self: ...
    @property
    def root(self) -> Element: ...
    def set_root_attr(self, attr: str, value: str | float) -> None: ...
    def set_width(self, width: float) -> None: ...
    def set_height(self, height: float) -> None: ...
    def set_view_box(self, view_box: ViewBox) -> None: ...
    def write(self, f: IO[bytes]) -> None: ...

class SvgImage(Image):
    image: SvgWrapper
    def __init__(self, image: SvgWrapper) -> None: ...
    def crop(
        self,
        rect: tuple[float, float, float, float],
        get_transformer: Callable[[SvgImage], ViewportToUserSpaceTransform] = ...,
    ) -> SvgImage: ...
    def resize(self, size: tuple[int, int]) -> SvgImage: ...
    def get_size(self) -> tuple[float, float]: ...
    def auto_orient(self) -> Self: ...
    def has_animation(self) -> bool: ...
    def get_frame_count(self) -> int: ...
    def write(self, f: IO[bytes]) -> None: ...
    def save_as_svg(self, f: IO[bytes]) -> SvgImageFile: ...
    @classmethod
    def open(cls, svg_image_file: IO[bytes] | SvgImageFile) -> SvgImage: ...
