import pathlib

from .image import image
from .product import product
from .exception import directory_image_exception

class directory_image:
    """
    This is image directory manager. It could store new images for product,
    move it, when product name had been changed, and also remove images.
    """

    def __init__(self, target: pathlib.Path, thumbnail: int = 400) -> None:
        """ 
        This initialize new manager.

        Parameters;
            target (pathlib.Path): Directory to store images in
            thumbnail (int): Dimension of the thumbnails
        """

        self.__target = target
        self.__thumbnail_size = thumbnail

        if not self.__target.is_dir():
            self.__target.mkdir()

    @property
    def thumbnail_size(self) -> int:
        """ Diameter of the thumbnails. """

        return self.__thumbnail_size

    def server_path() -> str:
        """ This return where bind covers on server. """

        return "/covers"

    @property
    def target(self) -> pathlib.Path:
        """ Target directory of the manager. """

        return self.__target

    def __name(self, target: product) -> str:
        """ 
        Base name of the image.
        
        Parameters: 
            target (product): Target product to generate name of

        Returns:
            (str): Base part of the name
        """

        return target.name.encode("UTF-8").hex()

    def get_full_name(self, target: product) -> str:
        """ 
        Name of the full size image.
        
        Parameters: 
            target (product): Target product to generate name of

        Returns:
            (str): Name of the full size file
        """

        return self.__name(target) + ".full.png"

    def get_thumbnail_name(self, target: product) -> str:
        """ 
        Name of the thumbnail.
        
        Parameters: 
            target (product): Target product to generate name of

        Returns:
            (str): Name of the thumnail file
        """

        return self.__name(target) + ".thumbnail.webp"

    def __full_path(self, target: product) -> pathlib.Path:
        """
        Path of the full size image.

        Parameters:
            target (product): Target product to generate path from

        Returns:
            (pathlib.Parh): Path of the image
        """

        return self.target / pathlib.Path(self.get_full_name(target))

    def __thumbnail_path(self, target: product) -> pathlib.Path:
        """
        Path of the thumbnail image.

        Parameters:
            target (product): Target product to generate path from

        Returns:
            (pathlib.Parh): Path of the thumbnail
        """

        return self.target / pathlib.Path(self.get_thumbnail_name(target))

    def save(self, content: image, target: product) -> None:
        """
        This save new image for new product.

        Parameters:
            coded (str): Base64 coded received image
            target (product): Target product to save image for
        """

        full = self.__full_path(target)
        thumbnail = self.__thumbnail_path(target)
       
        if full.is_file() or thumbnail.is_file(): 
            content = "Images for product \"" + target.name + "\" "
            content = content + "already exists."

            raise directory_image_exception(content)

        content \
        .save_full(full) \
        .save_thumbnail(thumbnail, self.thumbnail_size)
    
    def drop(self, target: product) -> None:
        """
        This drop images for given product.

        Parameters:
            target (product): Target product to remove images for
        """

        full = self.__full_path(target)
        thumbnail = self.__thumbnail_path(target)
        
        if not full.is_file() or not thumbnail.is_file():
            content = "Can not remove images for \"" + target.name + "\" "
            content = content + "it not exiets."

            raise directory_image_exception(content)

        full.unlink()
        thumbnail.unlink()

    def update(self, old: product, new: product) -> None:
        """
        This update names of the images for product. Name of the images is
        connected with name of the product, and when name of the product 
        had been changed, also images must be updated.

        Parameters:
            old (product): Product before update
            new (product): Product after update
        """

        same_name = (
            self.get_thumbnail_name(old) == self.get_thumbnail_name(new) and \
            self.get_full_name(old) == self.get_full_name(new)
        )

        if same_name:
            return

        old_full = self.__full_path(old)
        old_thumbnail = self.__thumbnail_path(old)

        if not old_full.is_file() or not old_thumbnail.is_file():
            content = "Can not move file for \"" + old.name + "\" "
            content = content + "because not exists."

            raise directory_image_exception(content)

        new_full = self.__full_path(new)
        new_thumbnail = self.__thumbnail_path(new)

        if new_full.is_file() or new_thumbnail.is_file(): 
            content = "Can not move, because images for \"" + new.name + "\" "
            content = content + "already exists."

            raise directory_image_exception(content)

        old_full.rename(new_full)
        old_thumbnail.rename(new_thumbnail)


