# -*- encoding: utf-8 -*-

from io import BytesIO

Path = None
random = None
subprocess = None
ImageCaptcha = None
ImageFilter = None
ImageOps = None
Image = None


def ensure_imported_Path():
    global Path
    from pathlib import Path


def ensure_imported_ImageFilter():
    global ImageFilter
    from PIL import ImageFilter


def ensure_imported_ImageOps():
    global ImageOps
    from PIL import ImageOps


def ensure_imported_ImageCaptcha():
    global ImageCaptcha
    from captcha.image import ImageCaptcha


def ensure_imported_Image():
    global Image
    from PIL.Image import Image


def ensure_imported_random():
    global random
    import random


def ensure_imported_subprocess():
    global subprocess
    import subprocess


class AbstractImageCaptchaGenerator:
    'Abstract class for generators for image captcha'

    def generate(self, secret: str, retry: int = 5) -> 'BytesIO':
        'Creates an captcha image with given secret'
        raise NotImplementedError(
            'This method should be overridden on the child class')

    def generate_bytes(self, secret: str, retry: int = 5) -> bytes:
        'Default implementation for unwrapping BytesIO\'s contents'
        return self.generate(secret, retry).getvalue()


class ImageCaptchaGenerator(AbstractImageCaptchaGenerator):
    'Generates image captcha using current process'

    def __init__(self, *args, **kwargs):
        'Initializes protected values'
        super().__init__(*args, **kwargs)
        self._image_captcha = _gen_image_captcha()
        ensure_imported_random()
        ensure_imported_Image()
        ensure_imported_ImageFilter()
        ensure_imported_ImageOps()

    def generate(self, secret: str, retry: int = 5) -> BytesIO:
        im: Image = self._image_captcha.generate_image(secret)
        im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.SMOOTH_MORE)
            im = im.copy()
        # if random.random() < 0.25:
        #     im = im.filter(ImageFilter.BLUR)
        #     im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.FIND_EDGES)
            im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.CONTOUR)
            im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.EMBOSS)
            im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.EDGE_ENHANCE_MORE)
            im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.DETAIL)
            im = im.copy()
        if random.random() < 0.25:
            im = im.filter(ImageFilter.SHARPEN)
            im = im.copy()
        if random.random() < 0.5:
            im = ImageOps.invert(im)
            im = im.copy()
        out = BytesIO()
        im.save(out, format='PNG')
        out.seek(0)
        return out


class ImageCaptchaSubprocessGenerator(AbstractImageCaptchaGenerator):
    'Generates image captcha on a subprocess'

    def __init__(self, *args, **kwargs):
        'Initializes protected values'
        super().__init__(*args, **kwargs)
        ensure_imported_subprocess()

    def generate(self, secret: str, retry: int = 5) -> BytesIO:
        result = subprocess.run(['python3', 'manage.py', 'gencaptcha', secret],
                                stdin=None,
                                stdout=subprocess.PIPE,
                                stderr=None,
                                text=False,
                                )
        if result.returncode:
            if retry > 0:
                return self.generate(secret, retry - 1)
            else:
                result.check_returncode()
        # print(result.stdout[:10])
        out = BytesIO(result.stdout)
        out.seek(0)
        return out


def _gen_image_captcha() -> 'ImageCaptcha':
    'Generates ImageCaptcha object'
    ensure_imported_Path()
    ensure_imported_ImageCaptcha()
    image_captcha_fonts = [
        str(Path('webproj/fonts/Roboto/Roboto-Regular.ttf').absolute()),
        str(Path('webproj/fonts/Fondamento/Fondamento-Regular.ttf').absolute()),
        str(Path('webproj/fonts/Josefin_Sans/static/JosefinSans-Medium.ttf').absolute()),
        str(Path('webproj/fonts/Lora/static/Lora-Medium.ttf').absolute()),
        str(Path('webproj/fonts/Quicksand/static/Quicksand-Regular.ttf').absolute()),
        str(Path('webproj/fonts/Work_Sans/static/WorkSans-Medium.ttf').absolute()),
    ]

    image_captcha = ImageCaptcha(300, 150,
                                 fonts=image_captcha_fonts,
                                 font_sizes=[36, 40, 44, 48, 54, 60, 66, 72])

    for _ in image_captcha.truefonts:
        pass

    return image_captcha
