from enum import Enum
from typing import Callable, Union, List, Optional

from numpy.typing import NDArray
from shapely import Polygon, MultiPolygon

from .contour import contour_inward, contour_outward
from .raster import (horizontal_left_to_right, horizontal_right_to_left,
                     vertical_bottom_to_top, vertical_top_to_bottom)
from .serpentine import serpentine_vertical, serpentine_horizontal
from ..beams import BeamType
from ..mill import Mill

_method_signature = Callable[[Union[Polygon, MultiPolygon], Mill, BeamType, Optional[bool]], List[NDArray]]
_method_map = {
    1: vertical_top_to_bottom,
    2: vertical_bottom_to_top,
    3: horizontal_left_to_right,
    4: horizontal_right_to_left,
    5: serpentine_vertical,
    6: serpentine_horizontal,
    7: contour_outward,
    8: contour_inward
}


class ScanStyle(Enum):

    @property
    def value(self) -> _method_signature:
        """Override value to return the corresponding function instead of the integer."""
        return _method_map[super().value]


class ScanStyles:

    class Sequential(ScanStyle):
        vertical_top_to_bottom = 1
        vertical_bottom_to_top = 2
        horizontal_left_to_right = 3
        horizontal_right_to_left = 4

    class Serpentine(ScanStyle):
        vertical = 5
        horizontal = 6

    class Contour(ScanStyle):
        outwards = 7
        inwards = 8
