# LICENSE: GPLv3
from PIL import Image
from base64 import b64encode as base64
from bottle import request, template, static_file, redirect, Bottle, Jinja2Template, jinja2_view, response
from collections import OrderedDict
from hashlib import sha1
from io import BytesIO
from pathlib import Path
import base58
import bottle
import functools
import json
import magic
import os
import sys
import traceback

config = json.load(open("config.json", "r"))
service_root = config["service_root"]
image_root = os.path.join(service_root, "images")
irpath = Path(image_root)

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

app = Bottle()

mime_detector = magic.Magic(mime=True)

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

@app.route('/')
@app.route('/page/<pagenr>')
@view("index.html")
def root(pagenr=0):
    try:
        pagenr = int(pagenr)
    except ValueError:
        return redirect("/", code=307)
    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[pagenr*config["n_thumbnails"]:(pagenr+1)*config["n_thumbnails"]]
    for image in images:
        generate_thumbnail(image)

    return {"filenames": images, "pagenr": pagenr}

def generate_thumbnail(filename):
    thumb_path = irpath / 'thumbs' / filename
    if (thumb_path.exists()):
        return

    try:
        img = Image.open(os.path.join(image_root, filename))
        width, height = img.size
        widthT, heightT = (256, (height*256)//width) if height > width else ((width * 256)//height, 256)
        midBox = (widthT // 2 - 128, heightT // 2 - 128, widthT // 2 + 128, heightT // 2 + 128)
        newImg = img.resize((widthT, heightT)).crop(midBox)
        newImg.save(str(thumb_path))
    except:
        traceback.print_exc()
        thumb_path.symlink_to(irpath / 'unparsable.png')

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

@app.route('/thumbs/:path#.+#', name='thumbs')
def thumbs(path):
    response = static_file(path, root=os.path.join(image_root, "thumbs"))
    response.add_header('Cache-Control', 'max-age=365000000, immutable')
    return response

@app.route('/images/:path#.+#', name='images')
def images(path):
    if ('favicon.ico' in path): return ''

    name = path.split('.', 1)[0]
    files = os.listdir(image_root)
    matches = [i for i in files if i.startswith(name)]

    matches.sort(key=lambda f: os.stat(os.path.join(image_root, f)).st_mtime)

    if (not matches):
        return redirect("/", code=307)

    if (shortest_uniq(files, matches[0]) == name):
        path = os.path.join(image_root, matches[0])
        mimetype = mime_detector.from_file(path)
        print(f"Serving {path} (detected mime type: {mimetype})", file=sys.stderr)
        response = static_file(matches[0], root=image_root, mimetype=mimetype)
        response.add_header('Content-Disposition', 'inline')
        return response

    if (len(matches) != 0):
        return redirect(shortest_uniq(files, matches[0]), code=307)

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()

    if config["use_base58_urls"]:
        digest = base58.b58encode_int(int(digest, 16))
        digest = digest.decode('utf-8')

    if (not extension):
        mimetype = mime_detector.from_buffer(buffer.getvalue())
        if (mimetype == 'image/png'): extension = '.png'
        if (mimetype == 'image/jpeg'): extension = '.jpg'

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

    return (digest + extension)

@app.route('/app_upload', method="POST")
def app_upload_image():
    filename = save_upload(request)
    files = os.listdir(image_root)
    return config["base_url"] + "{}".format(shortest_uniq(files, filename))

@app.route('/upload', method="POST")
def upload_image():
    filename = save_upload(request)
    # code is 302 to change method to GET
    return redirect("/{}".format(filename), code=302)


@app.route('/<name>')
def get(name):
    return images(name)
    files = os.listdir(image_root)
    matches = [i for i in files if i.startswith(name)]

    matches.sort(key=lambda f: os.stat(os.path.join(image_root, f)).st_mtime)

    print(matches)

    if (not matches):
        return redirect("/", code=307)

    if (shortest_uniq(files, matches[0]) == name):
        return {"filename": os.path.join("images", matches[0])}

    if (len(matches) != 0):
        return redirect(shortest_uniq(files, matches[0]), code=307)


app.catchall = False # report errors to uWSGI
