import imghdr
from os import path
from typing import Tuple, Optional

from PIL.Image import Image
from PIL import Image as PilImage, ImageChops


class MangaImage:
    _image = None  # type: Image
    src_path = None  # type: str

    def __init__(self, src_path):
        """
        :param src_path:
        """
        if not path.isfile(src_path):
            raise AttributeError('Image not found')

        self.src_path = src_path
        self._image = PilImage.open(src_path)

    @staticmethod
    def new(mode: str, size: Tuple[int, int]):
        return PilImage.new(mode, size)

    @property
    def image(self) -> Image:
        """
        :rtype: Image
        :return:
        """
        return self._image

    @image.setter
    def image(self, image: Image):
        self._image = image

    def gray(self, dest_path: str):
        """
        :param dest_path:
        :return:
        """
        try:
            image = self.image.convert('LA')
        except (ValueError, OSError):
            image = self.image.convert('L')
        if dest_path is not None:
            image.save(dest_path)
        return image

    def convert(self, dest_path: str, quality: int = 95):
        """
        see http://pillow.readthedocs.io/en/3.4.x/handbook/image-file-formats.html
        :param dest_path:
        :param quality:
        :return:
        """
        self.image.save(dest_path, quality=quality)
        return dest_path

    def crop_manual_with_offsets(self, offsets, dest_path: str):
        """
        :param offsets:
        :param dest_path:
        :return:
        """
        left, upper, right, lower = offsets
        width, height = self.image.size
        image = self.image.crop((
            left,
            upper,
            width - right,
            height - lower
        ))
        image.save(dest_path)

    def crop_manual(self, sizes: tuple, dest_path: str):
        """
        :param sizes: The crop rectangle, as a (left, upper, right, lower)-tuple.
        :param dest_path:
        :return:
        """
        self.image.crop(sizes).save(dest_path)

    def crop_auto(self, dest_path: str):
        """
        :param dest_path:
        :return:
        """
        bg = PilImage.new(
            self.image.mode,
            self.image.size,
            self.image.getpixel((0, 0))
        )
        diff = ImageChops.difference(self.image, bg)
        diff = ImageChops.add(diff, diff, 2.0, -100)
        bbox = diff.getbbox()
        if bbox:
            crop = self.image.crop(bbox)
            if dest_path:
                crop.save(dest_path)

    def close(self):
        self.image is not None and self.image.close()

    @staticmethod
    def real_extension(_path):
        img = imghdr.what(_path)
        if img:
            return '.' + img
        return None

    @staticmethod
    def is_image(_path) -> bool:
        return imghdr.what(_path) is not None
