#!venv/bin/python
import pathlib
import posixpath

import click
import ghp_import
import logging
import httpx
import jinja2
import markdown

import xml.etree.ElementTree as etree


pages = {
    '/': 'docs/index.md',
    '/quickstart': 'docs/quickstart.md',
    '/clients': 'docs/clients.md',
    '/servers': 'docs/servers.md',
    '/requests': 'docs/requests.md',
    '/responses': 'docs/responses.md',
    '/urls': 'docs/urls.md',
    '/headers': 'docs/headers.md',
    '/content-types': 'docs/content-types.md',
    '/connections': 'docs/connections.md',
    '/networking': 'docs/networking.md',
    '/about': 'docs/about.md',
}

def path_to_url(path):
    if path == "index.md":
        return "/"
    return f"/{path[:-3]}"


class URLsProcessor(markdown.treeprocessors.Treeprocessor):
    def __init__(self, state):
        self.state = state

    def run(self, root: etree.Element) -> etree.Element:
        for element in root.iter():
            if element.tag == 'a':
                key = 'href'
            elif element.tag == 'img':
                key = 'src'
            else:
                continue

            url_or_path = element.get(key)
            if url_or_path is not None:
                output_url = self.rewrite_url(url_or_path)
                element.set(key, output_url)

        return root

    def rewrite_url(self, href: str) -> str:
        if not href.endswith('.md'):
            return href

        current_url = path_to_url(self.state.file)
        linked_url = path_to_url(href)
        return posixpath.relpath(linked_url, start=current_url)


class BuildState:
    def __init__(self):
        self.file = ''


state = BuildState()
env = jinja2.Environment(
    loader=jinja2.FileSystemLoader('docs/templates'),
    autoescape=False
)
template = env.get_template('base.html')
md = markdown.Markdown(extensions=['fenced_code'])
md.treeprocessors.register(
    item=URLsProcessor(state),
    name='urls',
    priority=10,
)


def not_found():
    text = httpx.Text('Not Found')
    return httpx.Response(404, content=text)


def web_server(request):
    if request.url.path not in pages:
        return not_found()

    file = pages[request.url.path]
    text = pathlib.Path(file).read_text()

    state.file = file
    content = md.convert(text)
    html = template.render(content=content).encode('utf-8')
    content = httpx.HTML(html)
    return httpx.Response(200, content=html)


@click.group()
def main():
    pass


@main.command()
def build():
    pathlib.Path("build").mkdir(exist_ok=True)

    for url, path in pages.items():
        basename = url.lstrip("/")
        output = f"build/{basename}.html" if basename else "build/index.html"
        text = pathlib.Path(path).read_text()
        content = md.convert(text)
        html = template.render(content=content)
        pathlib.Path(output).write_text(html)
        print(f"Built {output}")


@main.command()
def serve():
    logging.basicConfig(
        format="%(levelname)s [%(asctime)s] %(name)s - %(message)s",
        datefmt="%Y-%m-%d %H:%M:%S",
        level=logging.INFO
    )

    with httpx.serve_http(web_server) as server:
        server.wait()


@main.command()
def deploy():
    ghp_import.ghp_import(
        "build",
        mesg="Documentation deploy",
        remote="origin",
        branch="gh-pages",
        push=True,
        force=False,
        use_shell=False,
        no_history=False,
        nojekyll=True,
    )
    print(f"Deployed to GitHub")


if __name__ == "__main__":
    main()
