from sys import argv
from subprocess import Popen, PIPE, STDOUT, run, call
from PIL import Image
from jinja2 import Environment, FileSystemLoader
from markdown import markdown
from glob import glob
from json import dump, dumps, load
from os import path
import re

numbers = re.compile("[0-9]+")
name_from_url = re.compile(r"https:\/\/helixnebula.space/(.*)/")
out_dir = "/var/www/html/"
gemini_out_dir = "/var/gemini/"
base_url = "https://helixnebula.space/"
md_dir = "/var/stories/"
template_environment = Environment(
    loader=FileSystemLoader("templates/"))

with open("metadata.json", "r") as f:
    metadata = load(f)

story_names = [
    path.basename(post).split('/')[-1][:-3] for post in glob(md_dir + "*")
]
story_names.sort()

for placename in metadata.keys():
    read_path = f"{out_dir}{placename}/"
    photos = [
            path.basename(photo).split('/')[-1] for photo in 
            glob(read_path + "*")
        ]
    try:
        photos.remove("index.html")
    except ValueError:
        pass
    metadata[placename]["count"] = len(photos)
    metadata[placename]["photos"] = photos
    metadata[placename]["photos"].sort(key=lambda path: int(numbers.search(path).group(0)))

with open(f"{out_dir}photos.json", "w") as f:
    dump(metadata, f)

def covers(overwrite=False):
    print("running covers")
    for placename, info in metadata.items():
        read_path = f"{out_dir}{placename}/{info['cover']}"
        write_path = f"{out_dir}cover/cover_{info['cover']}"
        if not overwrite and path.exists(write_path):
            continue
        command = ["convert", read_path, "-strip", "-interlace", "Plane", "-gaussian-blur", "0.05",
                   "-auto-orient", "-resize", "700x525>", "-quality", "80%", write_path]
        run(command)

def thumbnails(overwrite=False):
    print("running thumbnails")
    for placename in metadata.keys():
        for photo in metadata[placename]["photos"]:
            read_path = f"{out_dir}{placename}/{photo}"
            write_path = f"{out_dir}thumbnail/thumbnail_{photo}"
            if not overwrite and path.exists(write_path):
                continue
            command = ["convert", read_path, "-strip", "-interlace", "Plane", "-gaussian-blur", "0.05",
                       "-auto-orient", "-resize", "300x200>", "-quality", "65%", write_path]
            run(command)

def compressed(overwrite=False):
    print("running compressed")
    for placename in metadata.keys():
        for photo in metadata[placename]["photos"]:
            read_path = f"{out_dir}{placename}/{photo}"
            write_path = f"{out_dir}compressed/compressed_{photo}"
            if not overwrite and path.exists(write_path):
                continue
            command = ["convert", read_path, "-auto-orient", "-strip", "-resize", "1200>", "-quality", "90%", write_path]
            run(command)

def render_index():
    template = template_environment.get_template("main")
    data = {key: value for key, value in sorted(metadata.items(), key=lambda item: item[1]['title'])}
    photo_counts = {placename: metadata[placename]["count"] for placename in metadata.keys()}
    total_count = 0
    posts = [
            path.basename(post).split('/')[-1][:-3] for post in 
            glob(md_dir + "*")
        ]
    posts.sort()
    for _, info in metadata.items():
        total_count = info["count"] + total_count
    with open(out_dir + "index.html", "w") as f:
        f.write(template.render({
            "metadata": data,
            "album_count": len(metadata.keys()),
            "photo_counts": photo_counts,
            "total_count": total_count,
            "posts": posts
        }))

def render_places():
    template = template_environment.get_template("place")
    for placename, info in metadata.items():
        working_path = out_dir + placename
        photos = metadata[placename]["photos"]
        photos_json = dumps(photos)
        count = len(photos)
        widths = []
        heights = []
        for photo in photos:
            photo_path = out_dir + "thumbnail/thumbnail_" + photo
            img = Image.open(photo_path)
            width, height = img.size
            widths.append(width)
            heights.append(height)
        photo_specs = zip(widths, heights, photos)
        try:
            with open(md_dir + placename + ".md", "r") as f:
                md = markdown(f.read())
        except FileNotFoundError:
            md = "<h1>No story (yet)</h1>"
        with open(working_path + "/index.html", "w") as f:
            f.write(template.render({
                "count": count,
                "placename": placename,
                "cover": info["cover"],
                "info": info,
                "markdown": md,
                "photos": photo_specs,
                "photos_json": photos_json
            }))

def sub_http_local_urls(match):
    name = match.group(1)
    if name in story_names:
        return name + ".gmi"
    else:
        return match.group(0)

def render_gemini_index():
    template = template_environment.get_template("gemini_main")
    with open(gemini_out_dir + "index.gmi", "w") as f:
        f.write(template.render({
            "post_info": {post_name: metadata[post_name]["title"] for post_name in story_names},
            "post_states": {post_name: metadata[post_name]["state"] for post_name in story_names}
        }))

def render_gemini_places():
    post_paths = glob(md_dir + "*")
    template = template_environment.get_template("gemini_place")
    for post_path in post_paths:
        post_name = path.basename(post_path).split('/')[-1][:-3]
        with open(post_path, "r") as f:
            content = f.read()
        process = Popen(["gemgen"], stdout=PIPE, stdin=PIPE, stderr=PIPE, text=True)
        gemtext = process.communicate(input=content)[0]
        gemtext_with_local_urls = name_from_url.sub(sub_http_local_urls, gemtext)
        with open(gemini_out_dir + post_name + ".gmi", "w") as f:
            f.write(template.render({
                "post_code": post_name,
                "post_body": gemtext_with_local_urls,
                "post_title": metadata[post_name]["title"],
                "state": metadata[post_name]["state"]
            }))

def copy_files():
    call("cp js/* html/js/", shell=True)
    call("cp style.css html/style.css", shell=True)

if __name__ == "__main__":
    try:
        overwrite = "overwrite" in argv
        covers(overwrite=overwrite)
        thumbnails(overwrite=overwrite)
        compressed(overwrite=overwrite)
    except KeyboardInterrupt:
        exit() 
    render_index()
    render_places()
    copy_files()
    render_gemini_index()
    render_gemini_places()