import base64
import os
import subprocess
from io import BytesIO

import magic
from PIL import Image

from distribusi.page_template import html_footer, html_head
from distribusi.mappings import CODE_TYPES, FILE_TYPES, SUB_TYPES
import re

MIME_TYPE = magic.Magic(mime=True)
PATTERN_TSTR = re.compile(r"(?P<tstring>(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2})T(?P<hour>\d{2})(?P<minute>\d{2})(?P<second>\d{2})(?P<timezone>[+|-]\d{4}))_(?P<name>.+)")
PATTERN_TSTR_TXT = re.compile(r"(?P<tstring>(?P<year>\d{4})(?P<month>\d{2})(?P<day>\d{2})T(?P<hour>\d{2})(?P<minute>\d{2})(?P<second>\d{2})(?P<timezone>[+|-]\d{4}))_(?P<name>.*)\.txt")


def caption(image):
    try:
        process = subprocess.Popen(
            ['exiftool', '-Comment', image], stdout=subprocess.PIPE)
        out, err = process.communicate()
    except Exception as e:
        print(e)
        print('Do you have exiftool installed?')
    try:
        caption = out.decode("utf-8").split(": ", 1)[1]
    except Exception as e:
        caption = ''
        print(e)
    return caption


def thumbnail(image, name, args):
    try:
        size = (450, 450)
        im = Image.open(image)
        im.thumbnail(size)

        if (im.mode == 'RGBA'):
            bg = Image.new('RGBA', im.size, (255,255,255))
            composite = Image.alpha_composite(bg, im)
            im=composite.convert('RGB')

        output = BytesIO()
        im.save(output, format='JPEG')
        im_data = output.getvalue()
        data_url = base64.b64encode(im_data).decode()
        if args.captions:
            cap = caption(image)
        else:
            cap = name
        return (
            "<figure><a href='{}'><img class='thumbnail' src='data:image/jpg;base64,{}'></a><figcaption>{}</figcaption></figure>"
        ).format(name, data_url, cap)
    except Exception as e:
        print('Thumbnailer:', e)
        return "<figure><a href='{}'><img src='{}'></a><figcaption>{}</figcaption></figure>".format(name, name, name)


def div(args, type_, subtype, tag, name):
    id_name = name.split('.')[0].replace(' ', '_')
    if args.no_filenames:
        filename = ''
    else:
        filename = '<span class="filename">{}</span>'.format(name)

    if 'image' in type_:
        html = '<div id="{}" class="{}">{}</div>'
    elif 'pdf' in subtype:
        html = '<div id="{}" class="{}">{}' + filename + '</div>'
    elif 'dir' in type_ or 'html' in subtype or 'unkown-file' in subtype:
        html = '<div id="{}" class="{}">{}</div>'
    else:
        html = '<div id="{}" class="{}">{}' + filename + '</div>'

    return html.format(id_name, subtype, tag)


def check_distribusi_index(args, index):
    """
    check whether a index.html file is generated by distribusi
    """

    if not args.force:
        with open(index, 'r') as f:
            if '<meta name="generator" content="distribusi" />' in f.read():
                return True
            else:
                if args.verbose:
                    print(index, 'not generated by distribusi, skipping')
                return False
    elif args.force:
        return True

def write_index(args,index, html, html_head, html_footer):
    with open(index, 'w') as f:
        if not args.no_template:
            if args.style:
                fs = open(args.style, "r")
                style = fs.read()
                styled_html_head = html_head % style
            else:
                styled_html_head = html_head % ''
            f.write(styled_html_head)

        for line in html:
            f.write(line + '\n')

        if not args.no_template:
            f.write(html_footer)


def render_dir(args, root):
    reverse = False
    if args.latest_first:
        reverse = True

    html = []

    for name in sorted(os.listdir(root),reverse=reverse):

        if args.no_hidden:
            if name.startswith('.'):
                continue

        if args.no_underscore:
            if name.startswith('_'):
                continue

        lv = root.split("/")
        relative = lv[len(lv) - 1]
        relative_path = "./{}/{}".format(relative, name)

        if os.path.isfile(root + '/' + name):

            if 'index.html' not in name:
                full_path = os.path.join(root, name)
                mime = MIME_TYPE.from_file(full_path)
                # example: MIME plain/text becomes 'type' plain 'subtype' text
                type_, subtype = mime.split('/')

                caption = name

                if args.verbose:
                    print('Found file in dir ', name, 'as', mime)

                if type_ in FILE_TYPES:
                    a = FILE_TYPES[type_].format(relative_path, caption)

                    # expansion for different kind of text files
                    if type_ == 'text':
                        if name.endswith('.html') or subtype == 'html':
                            subtype = 'html'
                            # what types of text files to expand
                            a = '<section id="{}">{}</section>'.format(name, open(full_path).read())
                        #elif subtype in CODE_TYPES or name.endswith('.txt'):
                        elif name.endswith('.txt'):
                            #check - time string
                            m = PATTERN_TSTR_TXT.search(name)
                            tstring = ""
                            rename = name
                            if m:
                                tstring = m.group('tstring')
                                rename = m.group('name')
                            if rename == "":
                                a = "<div>"
                            else:
                                a = "<div><div class='named'>{}</div>".replace('{}', rename)
                            a = a + open(full_path).read() + "</div><time datetime={}>{}</time>"
                            a = a.replace('{}', tstring)
                        else:
                            subtype = subtype + ' unkown-file'
                            a = "<a href='{}'>{}</a>".format(relative_path, caption)
                            # a = FILE_TYPES[type_]

                    if type_ == 'image':
                        if args.thumbnail:
                            a = thumbnail(relative_path, relative_path, args)
                        if args.no_filenames:
                            caption = ""
                        if args.captions:
                            caption = caption(relative_path)
                        a = FILE_TYPES[type_].format(relative_path, caption)

                if subtype in SUB_TYPES:
                    a = SUB_TYPES[subtype]

                if type_ not in FILE_TYPES and subtype not in SUB_TYPES:
                    # catch exceptions not yet defined in FILE_TYPES or SUB_TYPES
                    a = "<a href='{}'>{}</a>".format(relative_path, caption)
                    if args.verbose:
                        message = 'not in list of file types, adding as plain href: \n'
                        print(type_, subtype, message, name)
                        subtype = subtype + ' unkown-file'

                a = a.replace('{}', relative_path)
                html.append(div(args, type_, subtype, a, name))

        if os.path.isdir(root + '/' + name):

            #check - time string
            m = PATTERN_TSTR.search(name)
            tstring = ""
            rename = name
            if m:
                tstring = m.group('tstring')
                rename = m.group('name')

            if args.menu_with_index:
                a = "<a href='{}/index.html'>{}</a><time datetime={}>{}</time>".format(relative_path, rename, tstring, tstring)
            else:
                a = "<a href='{}'>{}/</a><time datetime={}>{}</time>".format(relative_path, rename, tstring, tstring)
            html.append(div(args, 'dir', 'dir', a, 'folder'))
            # html.insert(0, div(args, 'dir', 'dir', a, 'folder'))

    result = ""
    for line in html:
        result += line + "\n"
    return result


def distribusify(args, directory):  # noqa

    reverse = False
    if args.latest_first:
        reverse = True

    for root, dirs, files in os.walk(directory):

        if args.exclude_directory:
            if args.verbose:
                print('Excluding directory:', ", ".join(args.exclude_directory))
            dirs[:] = [d for d in dirs if d not in args.exclude_directory]

        if args.no_hidden:
            dirs = list(filter(lambda d: not d.startswith('.'), dirs))
            files = list(filter(lambda f: not f.startswith('.'), files))

        if args.no_underscore:
            dirs = list(filter(lambda d: not d.startswith('_'), dirs))
            files = list(filter(lambda f: not f.startswith('_'), files))

        dirs.sort()
        files.sort()

        if not args.remove_index:
            html = []

            if args.verbose:
                print('Generating directory listing for', root)

            for name in sorted(files,reverse=reverse):

                if 'index.html' not in name:
                    full_path = os.path.join(root, name)
                    mime = MIME_TYPE.from_file(full_path)
                    # example: MIME plain/text becomes 'type' plain 'subtype' text
                    type_, subtype = mime.split('/')

                    caption = name

                    if args.verbose:
                        print('Found', name, 'as', mime)

                    if type_ in FILE_TYPES:

                        a = FILE_TYPES[type_].format(name, caption)

                        # expansion for different kind of text files
                        if type_ == 'text':
                            if name.endswith('.html') or subtype == 'html':
                                subtype = 'html'
                                # what types of text files to expand
                                a = '<section id="{}">{}</section>'.format(name, open(full_path).read())
                            #elif subtype in CODE_TYPES or name.endswith('.txt'):
                            elif name.endswith('.txt'):
                                #check - time string
                                m = PATTERN_TSTR_TXT.search(name)
                                tstring = ""
                                rename = name
                                if m:
                                    tstring = m.group('tstring')
                                    rename = m.group('name')
                                if rename == "":
                                    a = "<div>"
                                else:
                                    a = "<div><div class='named'>{}</div>".replace('{}', rename)
                                a = a + open(full_path).read() + "</div><time datetime={}>{}</time>"
                                a = a.replace('{}', tstring)
                            else:
                                subtype = subtype+' unkown-file'
                                a = "<a href='{}'>{}</a>"
                                # a = FILE_TYPES[type_]

                        if type_ == 'image':
                            if args.thumbnail:
                                a = thumbnail(full_path, name, args)
                            if args.no_filenames:
                                caption = ""
                            if args.captions:
                                caption = caption(full_path)
                            a = FILE_TYPES[type_].format(name, caption)

                    if subtype in SUB_TYPES:
                        a = SUB_TYPES[subtype]

                    if type_ not in FILE_TYPES and subtype not in SUB_TYPES:
                        # catch exceptions not yet defined in FILE_TYPES or SUB_TYPES
                        a = "<a href='{}'>{}</a>"
                        if args.verbose:
                            message = 'not in list of file types, adding as plain href: \n'
                            print(type_, subtype, message, name)
                            subtype = subtype + ' unkown-file'

                    a = a.replace('{}', name)

                    html.append(div(args, type_, subtype, a, name))

            if root != directory:
                if args.menu_with_index:
                    html.append('<a href="../index.html">../</a>')
                else:
                    html.append('<a href="../">../</a>')

            for name in sorted(dirs,reverse=reverse):

                #check - time string
                m = PATTERN_TSTR.search(name)
                tstring = ""
                rename = name
                if m:
                    tstring = m.group('tstring')
                    rename = m.group('name')

                if args.menu_with_index:
                    a = "<div class='title'><a href='{}/index.html'>{}</a><time datetime={}>{}</time></div>".format(name, rename, tstring, tstring)
                else:
                    a = "<div class='title'><a href='{}'>{}/</a><time datetime={}>{}</time></div>".format(name, rename, tstring, tstring)
                if args.unfolding:
                    rd = render_dir(args, "{}/{}".format(root, name))
                    h = '<div id="folder-{}" class="unfolded">\n{}\n{}</div>'.format(name, a, rd)
                    if root != directory:
                        html.insert(-1, h)
                    else:
                        html.append(h)
                else:
                    html.insert(0, div(args, 'dir', 'dir', a, 'folder'))

            index = os.path.join(root, 'index.html')
            if os.path.exists(index):
                if check_distribusi_index(args, index):
                   write_index(args,index,html, html_head, html_footer)
            elif not os.path.exists(index):
                write_index(args,index,html, html_head, html_footer)

        if args.remove_index:
            index = os.path.join(root, 'index.html')
            if 'index.html' in files:
                try:
                    if check_distribusi_index(args, index):
                        if args.verbose:
                            print('Removing index.html from', root)
                        os.remove(index)
                except Exception as e:
                    print(e)
