import numpy as np
from numpy import ndarray
from numpy.typing import ArrayLike, NDArray
from vispy.visuals.transforms.linear import STTransform

from ...geometry import Rect
from ...util import transforms
from ._util import arg_to_vec4, as_vec4
from .base_transform import BaseTransform

# -*- coding: utf-8 -*-
# Copyright (c) Vispy Development Team. All Rights Reserved.
# Distributed under the (new) BSD License. See LICENSE.txt for more info.

class NullTransform(BaseTransform):
    glsl_map: str = ...
    glsl_imap: str = ...

    Linear: bool = ...
    Orthogonal: bool = ...
    NonScaling: bool = ...
    Isometric: bool = ...

    @arg_to_vec4
    def map(self, coords: ArrayLike): ...
    def imap(self, coords: ArrayLike): ...
    def __mul__(self, tr): ...
    def __rmul__(self, tr): ...

class STTransform(BaseTransform):
    glsl_map: str = ...

    glsl_imap: str = ...

    Linear: bool = ...
    Orthogonal: bool = ...
    NonScaling: bool = ...
    Isometric: bool = ...

    def __init__(self, scale: ArrayLike | None = None, translate: ArrayLike | None = None): ...
    @arg_to_vec4
    def map(self, coords: ArrayLike) -> NDArray: ...
    @arg_to_vec4
    def imap(self, coords: ArrayLike) -> NDArray: ...
    def shader_map(self): ...
    def shader_imap(self): ...
    @property
    def scale(self): ...
    @scale.setter
    def scale(self, s): ...
    @property
    def translate(self): ...
    @translate.setter
    def translate(self, t): ...
    def _set_st(self, scale=None, translate=None, update=True): ...
    def _update_shaders(self): ...
    def move(self, move: ArrayLike): ...
    def zoom(self, zoom: ArrayLike, center: ArrayLike = ..., mapped: bool = True): ...
    def as_matrix(self): ...
    @classmethod
    def from_mapping(cls, x0: ArrayLike, x1: ArrayLike) -> STTransform: ...
    def set_mapping(self, x0: ArrayLike, x1: ArrayLike, update: bool = True): ...
    def __mul__(self, tr): ...
    def __rmul__(self, tr): ...
    def __repr__(self): ...

class MatrixTransform(BaseTransform):
    glsl_map: str = ...

    glsl_imap: str = ...

    Linear: bool = ...
    Orthogonal: bool = ...
    NonScaling: bool = ...
    Isometric: bool = ...

    def __init__(self, matrix: ArrayLike | None = None): ...
    @arg_to_vec4
    def map(self, coords: ArrayLike) -> NDArray: ...
    @arg_to_vec4
    def imap(self, coords: ArrayLike) -> NDArray: ...
    def shader_map(self): ...
    def shader_imap(self): ...
    @property
    def matrix(self): ...
    @matrix.setter
    def matrix(self, m): ...
    @property
    def inv_matrix(self): ...
    @arg_to_vec4
    def translate(self, pos: np.ndarray): ...
    def scale(self, scale: ArrayLike, center: ArrayLike | None = None): ...
    def rotate(self, angle: float, axis: ArrayLike): ...
    def set_mapping(self, points1: ArrayLike, points2: ArrayLike): ...
    def set_ortho(self, l: float, r: float, b: float, t: float, n: float, f: float): ...
    def reset(self): ...
    def __mul__(self, tr): ...
    def __repr__(self): ...
    def set_perspective(self, fov: float, aspect: float, near: float, far: float): ...
    def set_frustum(self, l: float, r: float, b: float, t: float, n: float, f: float): ...

# class SRTTransform(BaseTransform):
#    """ Transform performing scale, rotate, and translate, in that order.
#
#    This transformation allows objects to be placed arbitrarily in a scene
#    much the same way MatrixTransform does. However, an incorrect order of
#    operations in MatrixTransform may result in shearing the object (if scale
#    is applied after rotate) or in unpredictable translation (if scale/rotate
#    is applied after translation). SRTTransform avoids these problems by
#    enforcing the correct order of operations.
#    """
#    # TODO
