import io
import PIL
import PIL.Image
import base64
import pathlib

from .exception import image_exception

class image:
    """ 
    This class is responsible for image storing. It get image coded as base64
    validate it, and when all went well, it could be saved and also thumbnail 
    could be generated.
    """

    def __init__(
        self, 
        coded: str, 
        max_size: int = 2 * 1024 * 1024 * 16
    ) -> None:
        """
        This initialize new image saver.

        Parameters:
            coded (str): Image as base64 content
            thumbnail (int): Diameters of image thumbnail (default = 400)
            max_size (int): Max size of image file (default = 16Mb)
        """

        if len(coded) > max_size:
            raise image_exception()

        self.__content = base64.standard_b64decode(coded)

        if not self.valid:
            raise image_exception()

    @property
    def content(self) -> bytes:
        """ Image as bytes. """

        return self.__content

    @property
    def __file(self) -> io.BytesIO:
        """  Image bytes as IO file like buffer. """

        return io.BytesIO(self.content)

    @property
    def __image(self) -> PIL.Image:
        """ New PIL Image object from received bytes. """

        try:
            return PIL.Image.open(self.__file)
        
        except:
            raise image_exception()
        
    def save_thumbnail(
        self, 
        location: pathlib.Path,
        diameter: int = 400
    ) -> object:
        """
        This save generated thumbnail in given location. Format of the 
        thumbnail is defined by location extension.
        
        Parameters:
            location (pathlib.Path): Place to store thumbnail

        Returns:
            (image): Self to chain dot calls
        """

        with self.__image as image:
            image.thumbnail((diameter, diameter))
            image.save(location)
        
        return self

    def save_full(self, location: pathlib.Path) -> object:
        """
        This save received image in given location. Format of the image is 
        based on the location extension.

        Parameters:
            location (pathlib.Path): Place to store image

        Returns:
            (image): Self to chain dot calls
        """

        with self.__image as image:
            image.save(location)

        return self

    @property
    def valid(self) -> bool:   
        """ True when image is valid, false when not. """

        try:
            with self.__image as image:
                image.verify()
                return True
        
        except:
            return False
