from bottle import request, route, run, template, static_file, redirect, Bottle, Jinja2Template, jinja2_view
from collections import OrderedDict
import os
import bottle
from PIL import Image, ImageOps
import functools
from io import BytesIO
from base64 import b64encode as base64
import json
from hashlib import sha1

config = json.load(open("./config.json", "r"))
image_root = config["image_root"]

Jinja2Template.settings = {'autoescape': True}
view = functools.partial(jinja2_view, template_lookup=["templates"])



def extensions(*args):
    def filter_fn(item):
        return os.path.splitext(item)[1] in args
    return filter_fn

def shortest_uniq(l, s):
    cur = ""
    i = 1
    while len([i for i in l if i.startswith(cur)])-1:
        cur = s[:i]
        i += 1
    return cur

@functools.lru_cache(maxsize=config["n_thumbnails"])
def generate_thumbnail(filename):
    data = BytesIO()
    image = Image.open(os.path.join(image_root, filename))

    thumb = ImageOps.fit(image, (96, 96), Image.ANTIALIAS)
    thumb.save(data, format='png')
    data.seek(0)
    return data.getvalue()


@route('/static/:path#.+#', name='static')
def static(path):
    return static_file(path, root="static")

@route('/images/:path#.+#', name='images')
def images(path):
    name = path
    files = os.listdir(image_root)
    print(name)
    matches = [i for i in files if i.startswith(name)]

    if (len(matches) == 1 and shortest_uniq(files, matches[0]) == name):
        return static_file(matches[0], root=image_root)
    elif (len(matches) == 1):
        return redirect("/images/"+shortest_uniq(files, matches[0]), code=307)
    elif (not matches):
        return redirect("/", code=307)
    else:
        print("unreachable!")

@route('/')
@view("index.html")
def root():
    images = list(filter(extensions(".jpg", ".jpeg", ".png"), os.listdir(image_root)))
    images.sort(key=lambda f: os.stat(os.path.join(image_root, f)).st_mtime, reverse=True)
    images = images[:config["n_thumbnails"]]
    thumbnails = map(generate_thumbnail, images)

    encoded_thumbnails = zip(images, map(base64, thumbnails))
    
    return {"thumbnails": OrderedDict(encoded_thumbnails)}

def save_upload(request):
    buffer = BytesIO()
    client_file = request.files.get('upload')
    client_file.save(buffer)
    
    extension = os.path.splitext(client_file.filename)[1]
    digest = sha1()
    digest.update(buffer.getvalue())
    digest = digest.hexdigest()

    server_file = open(os.path.join(image_root, digest + extension), "wb")
    server_file.write(buffer.getvalue())
    server_file.close()

    return (digest + extension)

@route('/app_upload', method="POST")
def app_upload_image():
    filename = save_upload(request)
    return "https://i.segfault.party/images/{}".format(filename)

@route('/upload', method="POST")
def upload_image():
    print("hueheuhuehue")
    filename = save_upload(request)
    return redirect("/{}".format(filename), code=307)


@route('/<name>')
@view('image.html')
def get(name):
    files = os.listdir(image_root)
    print(name)

    matches = [i for i in files if i.startswith(name)]
    print(matches)

    if (len(matches) == 1 and shortest_uniq(files, matches[0]) == name):
        return {"filename": os.path.join("images", matches[0])}
    elif (len(matches) == 1):
        return redirect(shortest_uniq(files, matches[0]), code=307)
    elif (not matches):
        return redirect("/", code=307)


# run(host="0.0.0.0", port=8080, server="python_server")
application = app = bottle.default_app()
application.catchall = False # report errors to uWSGI
