import abc
import numpy as np
from .math.rotate import rotate as rotate
from abc import ABC, abstractmethod
from typing import Any, Callable, Iterable, Sequence, Union

LikeProperty: Any
PropertySequence = Sequence[LikeProperty]

class Property(ABC, metaclass=abc.ABCMeta):
    @abstractmethod
    def get(self) -> Any: ...
    @property
    def value(self) -> Any: ...
    def transform(self, operation: Operation, **kwargs) -> Property: ...

class ConstantProperty(Property):
    def __init__(self, value) -> None: ...
    def get(self) -> Any: ...

def as_property(value: LikeProperty) -> Property: ...

class Source(Property):
    def __init__(self, fn: Callable, *args, **kwargs) -> None: ...
    def get(self) -> Any: ...

class Convert(Source):
    def __init__(self, p: LikeProperty, fn: Callable, *args, **kwargs) -> None: ...
    def get(self) -> Any: ...

class Iter(Property):
    def __init__(self, seq: Iterable) -> None: ...
    def get(self) -> Any: ...

class RandomUniform(Property):
    def __init__(self, low: float = ..., high: float = ...) -> None: ...
    def get(self): ...

class Point(Property):
    def __init__(self, point: PropertySequence) -> None: ...
    def get(self) -> np.ndarray: ...
LikePoint = Union[Point, PropertySequence]

def as_point(value: LikePoint) -> Point: ...

class PointCloud(Point):
    def __init__(self, points: Sequence[LikePoint]) -> None: ...
    def transform(self, operation: Operation, **kwargs) -> Point: ...
LikePointCloud = Union[PointCloud, Sequence[LikePoint]]

def as_pointcloud(value: LikePointCloud) -> PointCloud: ...

class Operation(metaclass=abc.ABCMeta):
    def __call__(self, **params) -> Callable: ...
    @abstractmethod
    def operation(self, obj, **params) -> Any: ...

class PointOperation(Operation, metaclass=abc.ABCMeta):
    def __call__(self, **params) -> Callable[[LikePoint], Point]: ...
    @abstractmethod
    def operation(self, obj: np.ndarray, **params) -> np.ndarray: ...

class PointShift(PointOperation):
    def __init__(self, shift: LikePoint) -> None: ...
    def __call__(self) -> Callable[[LikePoint], Point]: ...
    def operation(self, obj: np.ndarray, shift: np.ndarray) -> np.ndarray: ...

class PointRotate(PointOperation):
    def __init__(self, angle: LikeProperty, pivot: LikePoint = ...) -> None: ...
    def __call__(self, pivot: LikePoint = ...) -> Callable[[LikePoint], Point]: ...
    def operation(self, obj: np.ndarray, pivot: np.ndarray, angle: np.ndarray) -> np.ndarray: ...

class PointInflation(PointOperation):
    def __init__(self, factor: LikeProperty, pivot: LikePoint = ...) -> None: ...
    def __call__(self, pivot: LikePoint = ...) -> Callable[[LikePoint], Point]: ...
    def operation(self, obj: np.ndarray, pivot: np.ndarray, factor: np.ndarray) -> np.ndarray: ...

class Transformator:
    def __init__(self, *operations: Operation) -> None: ...
    def __call__(self, instance: Property) -> Property: ...
