from sh import convert as conv_unbaked, composite as comp_unbaked, identify as ident_unbaked
import logging
import magic
import re
from . import command, photo_fn, update_to_message
from io import StringIO, BytesIO

logger = logging.getLogger("scale")
config = None

# disable _tty_out to compact the AppArmor profile :)
convert = conv_unbaked.bake(_tty_out=False)
composite = comp_unbaked.bake(_tty_out=False)
identify = ident_unbaked.bake(_tty_out=False)

mime_detector = magic.Magic(mime=True)

def get_file_dims(fname):
    s = StringIO()
    identify(fname, _out=s)
    string = s.getvalue()
    return [*map(int, (string.split()[2]).split('x'))]

def linesplit(text, linelen=None):
    # we don't want one line of really long text. try to limit text to ~15 chars per line.
    inner_lines = text.strip().split('\n')
    words = text.split()
    lines = []
    line = ""

    if not linelen:
        linelen = 15
        if (len(text) > 50):
            linelen = 22
        if len(text) < 20:
            linelen = 10

    if len(inner_lines) != 1:
        for line in inner_lines:
            lines.append(linesplit(line.strip(), linelen))
        return '\n'.join(lines)

    for word in words:
        l = len(word) + 1
        if (line != "" and len(line) + l > linelen):
            lines.append(line)
            line = word
        elif (line == ""):
            line = word
        else:
            line += f" {word}"
    lines.append(line)
    return '\n'.join(lines)

def leonzegt_text(text):
    args = "-background transparent -fill #241e1e -gravity center -font DejaVu-Sans -size 244x188".split()
    composite_args = "-compose Over -geometry +284+265 text2.png leonblank.png leonzegt.png".split()

    convert(*args, f'label:{text}', 'text.png')
    convert('text.png', '-background', 'transparent', '-rotate', '28', 'text2.png')
    composite(*composite_args)
    return open('leonzegt.png', 'rb')


@command('Beon: (.+)', pass_groups=True, prefix=False)
def leonzegt(bea, bot, update, groups):
    """ Als Leon iets zegt, maar niemand hoort het, zegt Leon dan wel iets? """
    label = linesplit(groups[0])
    f = leonzegt_text(label)

    update.message.reply_photo(photo=f, quote=False)

@update_to_message
def rescale_bypass(message):
    txt = ""
    if (message.reply_to_message):
        txt = message.text
    else:
        txt = message.caption
    return (message.chat_id in config['autorescale_chat_ids']) and (not txt or not txt.startswith('Bea'))

def rescale_image(image_io, extension):
    size = '35%'
    xresize = 35
    yresize = 35

    fname = 'cas'+extension

    with open(fname, 'wb') as f:
        f.write(image_io.read())

    sz = get_file_dims(fname)
    transformed_width = sz[0] * (xresize/100)
    transformed_height = sz[1] * (yresize/100)

    result_size = transformed_width * transformed_height
    if result_size > 10e6:
        raise ValueError("resulting image would be too big (>10MP)")

    convert(fname, '-liquid-rescale', size, 'output.png')
    convert('output.png', '-liquid-rescale', f"{sz[0]}x{sz[1]}", 'output2.png')
    final_file = 'output2.png'

    data = open(final_file, 'rb')
    return data


@command('(?:rescale|herschaliseer)',
         pass_groups=True, additional_match_fn=photo_fn, bypass_fn=rescale_bypass)
def rescale(bea, bot, update, photo, groups):
    """ Content-aware scale an image. """
    if (hasattr(photo, "width")):
        sz = photo.width, photo.height
    elif (not photo.file_size):
        return update.message.reply_text("Is this a file? If so, it won't tell me its file size, so I won't download it.")
    elif (photo.file_size > 10e6):
        return update.message.reply_text("10 megabytes is too big for me chief.")

    buf = BytesIO()

    fl = photo.get_file()
    fl.download(out=buf)
    buf.seek(0)

    mimetype = mime_detector.from_buffer(buf.getvalue())
    if (mimetype == 'image/png'):
        extension = '.png'
    elif (mimetype == 'image/jpeg'):
        extension = '.jpg'
    else:
        logger.info(f"Got 'photo' with MIME type {mimetype}.")
        return


    bea.start_uploading_photo()

    try:
        f = rescale_image(buf, extension)
    except ValueError as e:
        return bea.reply(f"rescale error: {e}")

    bea.stop_uploading_photo()
    update.message.reply_photo(photo=f)

@command('nepsticker', additional_match_fn=photo_fn)
def webp_convert(bea, bot, update, photo):
    """ Turn an image into a 'fake sticker', i.e. a .webp image. """
    photo.get_file().download('webpin.png')
    convert('webpin.png', '-resize', '512x512', 'webpout.webp')
    update.message.reply_sticker(open('webpout.webp', 'rb'))

@command('convert (.+)', additional_match_fn=photo_fn, pass_groups=True, auth=True)
def im_command(bea, bot, update, photo, groups):
    photo.get_file().download('im_in.png')
    convert('im_in.png', *groups[0].split(), 'im_out.png')
    update.message.reply_photo(photo=open('im_out.png', 'rb'))

@command('512', additional_match_fn=photo_fn)
def stickersize(bea, bot, update, photo):
    """
    Turn an image into a 512x512 png file, ready to be stickerified. Also take a look at Bea's sticker features!
    """
    photo.get_file().download('stickerin.png')
    convert('stickerin.png', '-resize', '512x512', 'stickerout.png')
    update.message.reply_document(document=open('stickerout.png', 'rb'), filename='sticker.png')

def init(bea, _config):
    global config
    config = _config
    return [rescale, webp_convert, im_command, stickersize, leonzegt]
