# vite - a simple and minimal static site generator, that JustWorks™
# Copyright (c) 2020 Anirudh Oppiliappan <x@icyphox.sh>
# Licensed under the MIT license

import sys
import pathlib
import os
import jinja2
import time
import http.server
import socketserver
import shutil
import datetime
import re

from myrkdown import markdown_path
from huepy import *
from livereload import Server
from subprocess import call


# constants
PAGES_PATH = "pages/"
BUILD_PATH = "build/"
TEMPL_PATH = "templates/"
TEMPL_FILE = ""
PORT = 1911


def import_config():
    try:
        sys.path.append(os.getcwd())
        globals()["config"] = __import__("config")
        global TEMPL_FILE
        TEMPL_FILE = os.path.join(TEMPL_PATH, config.template)
    except ImportError:
        print(bad("Error: config.py not found."))
        print(que("Are you sure you're in a project directory?"))
        sys.exit(1)


def create_project(path):
    try:
        abs_path = pathlib.Path(path).resolve()
        cur_path = pathlib.Path(".").resolve()
        os.makedirs(os.path.join(path, "build"))
        os.mkdir(os.path.join(path, "pages"))
        os.mkdir(os.path.join(path, "templates"))
        os.mkdir(os.path.join(path, "static"))
        create_config(path)
        create_template(path)
        print(good("Created project directory at %s." % (abs_path)))
    except FileExistsError:
        print(bad("Error: specified path exists."))


def create_path(path):
    head, tail = os.path.split(path)
    now = datetime.datetime.now()
    today = now.strftime("%Y-%m-%d")
    url = os.path.splitext(os.path.basename(path))[0]

    try:
        os.makedirs(os.path.join(PAGES_PATH, head))
    except FileExistsError:
        pass
    if os.path.exists(os.path.join(PAGES_PATH, head, tail)):
        print(bad("Error: specified path exists."))
    else:
        with open(os.path.join(PAGES_PATH, head, tail), "w") as f:
            to_write = (
                """---
template:
url: {u}
title:
subtitle:
date: {t}
---\n"""
            ).format(t=today, u=url)
            f.write(to_write)
        print(good("Created %s.") % (os.path.join(PAGES_PATH, head, tail)))


def create_config(path):
    with open(os.path.join(path, "config.py"), "w") as f:
        f.write(
            """# config.py - Vite's configuration script

title = ''
author = ''
header = ''
footer = '' 
pre_build = []
post_build = []
template = 'index.html'  # default is index.html\n"""
        )


def create_template(path):
    with open(os.path.join(path, "templates", "index.html"), "w") as f:
        f.write(
            """<!DOCTYPE html>
<html>
<header>
        {{ header }}
        <title>
                {{ title }}     
        </title>
</header>

<body>
        {{ body }}
</body>

<footer>
        {{ footer }}
        <p> {{ author }} </p>
<footer>

                """
        )


# jinja2
def jinja_render(html, tmpl):
    template_loader = jinja2.FileSystemLoader("./")
    env = jinja2.Environment(loader=template_loader)
    try:
        template = env.get_template(tmpl)
    except jinja2.exceptions.TemplateNotFound:
        template = env.get_template(TEMPL_FILE)
    meta = html.metadata
    output = template.render(
        title=meta["title"] if "title" in meta else config.title,
        author=meta["author"] if "author" in meta else config.author,
        header=meta["header"] if "header" in meta else config.header,
        url=meta["url"] if "url" in meta else "",
        footer=meta["footer"] if "footer" in meta else config.footer,
        date=meta["date"] if "date" in meta else "",
        subtitle=meta["subtitle"] if "subtitle" in meta else "",
        body=html,
    )
    return output


def fm_template(metadata):
    try:
        page_template = os.path.join(os.path.join(TEMPL_PATH, metadata["template"]))
    except KeyError:
        page_template = TEMPL_FILE
    return page_template


def markdown_render(filename):
    html = markdown_path(
        os.path.join(PAGES_PATH, filename),
        extras=[
            "metadata",
            "fenced-code-blocks",
            "header-ids",
            "footnotes",
            "smarty-pants",
            "tables",
            "link-patterns",
        ],
        link_patterns=[
            (
                re.compile(
                    r"((([A-Za-z]{3,9}:(?:\/\/)?)(?:[\-;:&=\+\$,\w]+@)?[A-Za-z0-9\.\-]+(:[0-9]+)?|(?:www\.|[\-;:&=\+\$,\w]+@)[A-Za-z0-9\.\-]+)((?:\/[\+~%\/\.\w\-_]*)?\??(?:[\-\+=&;%@\.\w_]*)#?(?:[\.\!\/\\\w]*))?)"
                ),
                r"\1",
            )
        ],
    )
    return html


def html_gen():
    def index_render(f, d=""):
        index_html = markdown_render(os.path.join(d, f))
        output = jinja_render(index_html, fm_template(index_html.metadata))
        with open(os.path.join(BUILD_PATH, d, "index.html"), "w") as ff:
            ff.write(output)
            if d:
                print(run("Rendered " + white("%s/%s") % (d, f)))
            else:
                print(run("Rendered " + white("%s") % (f)))

    def normal_render(f, d=""):
        html_text = markdown_render(os.path.join(d, f))
        html_file = os.path.splitext(os.path.join(BUILD_PATH, d, f))[0]
        os.mkdir(html_file)
        output = jinja_render(html_text, fm_template(html_text.metadata))
        with open(os.path.join(html_file, "index.html"), "w") as ff:
            ff.write(output)
            if d:
                print(run("Rendered " + white("%s/%s") % (d, f)))
            else:
                print(run("Rendered " + white("%s") % (f)))

    for root, dirs, files in os.walk(PAGES_PATH):
        for d in dirs:
            os.mkdir(os.path.join(BUILD_PATH, d))
            for f in os.listdir(os.path.join(PAGES_PATH, d)):
                if os.path.splitext(f)[1] != ".md":
                    shutil.copyfile(
                        os.path.join(PAGES_PATH, d, f), os.path.join(BUILD_PATH, d, f)
                    )
                    print(run("Copied " + white("%s/%s") % (d, f)))
                elif f == "_index.md":
                    index_render(f, d)
                else:
                    normal_render(f, d)

    for f in os.listdir(PAGES_PATH):
        if os.path.isfile(os.path.join(PAGES_PATH, f)):
            if os.path.splitext(f)[1] != ".md":
                shutil.copyfile(
                    os.path.join(PAGES_PATH, f), os.path.join(BUILD_PATH, f)
                )
                print(run("Copied " + white("%s") % (f)))
            elif f == "_index.md":
                index_render(f)
            else:
                normal_render(f)


def server():
    #    handler = http.server.SimpleHTTPRequestHandler
    #    os.chdir(os.path.join(os.getcwd(), BUILD_PATH))
    server = Server()
    try:
        print(
            run(
                f'Serving the {italic(yellow("build"))} directory at {white(f"http://localhost:{PORT}")}'
            )
        )
        print(white("Ctrl+C") + " to stop.")
        server.serve(port=PORT, root="build/")
    except KeyboardInterrupt:
        print(info("Stopping server."))
        sys.exit(1)


def clean():
    for root, dirs, files in os.walk(BUILD_PATH):
        for f in files:
            os.unlink(os.path.join(root, f))
        for d in dirs:
            shutil.rmtree(os.path.join(root, d))


def builder():
    path = os.getcwd()
    start = time.process_time()
    if not os.listdir(os.path.join(path, PAGES_PATH)):
        print(info(italic("pages") + " directory is empty. Nothing to build."))
        sys.exit(1)
    else:
        try:
            if config.pre_build != "":
                print(run("Running pre-build actions..."))
                for s in config.pre_build:
                    print(info(f"{s}"))
                    call(s)
        except AttributeError:
            pass
        clean()
        html_gen()
        if os.path.exists(os.path.join(os.getcwd(), "static")):
            shutil.copytree(
                os.path.join(os.getcwd(), "static"), os.path.join(BUILD_PATH, "static")
            )
        try:
            if config.post_build != "":
                print(run("Running post-build actions..."))
                for s in config.post_build:
                    print(info(f"{s}"))
                    call([s])
        except AttributeError:
            pass

        print(good("Done in %0.5fs." % (time.process_time() - start)))