from rich import print as rprint
import git
from util import *
from jinja2 import Environment, FileSystemLoader, select_autoescape
import fire
from collections.abc import Callable
import process
import functools
import shutil
from pathlib import Path
import os
import time


def make_absurl_filter(site_conf: any) -> Callable[[str], str]:
    return functools.partial(get_absolute_url, site_conf)


class CLI:
    @staticmethod
    def generate(
        base_dir: str = "site", output_dir: str = "_dist", production: bool = False
    ):
        start = time.time()
        
        base_dir = Path(base_dir)
        output_dir = Path(output_dir)
        html_dir = output_dir / "html"

        if output_dir.exists() and not is_directory_empty(output_dir):
            rprint(
                WARN_LEADER
                + f"A directory called [bold]{output_dir}[/bold] already exists and is not "
                f"empty"
            )

        with open(base_dir / "config.yml") as f:
            site_config = load_yaml(f.read())
            assert (
                "build" not in site_config
            ), "build section of site config must not exist so it can be written at runtime"
            site_config["build"] = {
                "hash": git.get_latest_commit_hash(base_dir)[:7],
                "date": git.get_latest_commit_datetime(base_dir),
            }

        jinja_env = build_jinja_env(site_config)

        # rprint(INFO_LEADER + "Processing content")
        process.content(base_dir, html_dir, jinja_env, site_config)
        # rprint(INFO_LEADER + "Processing blog")
        process.blog(base_dir, html_dir, jinja_env, site_config)
        # rprint(INFO_LEADER + "Generating Caddy config")
        process.caddy_config(base_dir, output_dir, jinja_env, site_config)
        # rprint(INFO_LEADER + "Processing Sass")
        process.sass(base_dir, output_dir)

        if production:
            # rprint(INFO_LEADER + "Compressing PNG")
            process.compress_png(output_dir)
            # rprint(INFO_LEADER + "Stripping EXIF data")
            process.strip_exif(output_dir)

        end = time.time()

        rprint(INFO_LEADER + f"Finished working in {round(end-start, 3)} seconds")

    @staticmethod
    def watch(base_dir: str = "site", output_dir: str = "_dist"):
        import inotify.adapters
        import inotify.constants
        import threading
        import http.server

        if os.path.exists(output_dir):
            rprint(WARN_LEADER + f"clobbering {output_dir}")

        def run():
            if os.path.exists(output_dir):
                shutil.rmtree(output_dir)
            CLI.generate(base_dir, output_dir=output_dir)

        debounced_run = debounce(1)(run)
        run()

        server = http.server.HTTPServer(
            ("127.0.0.1", 8000),
            lambda a, b, c: http.server.SimpleHTTPRequestHandler(
                a, b, c, directory=Path(output_dir) / "html"
            ),
        )
        threading.Thread(target=server.serve_forever, daemon=True).start()

        i = inotify.adapters.InotifyTree(base_dir, mask=inotify.constants.IN_CLOSE_WRITE|inotify.constants.IN_MOVE|inotify.constants.IN_CREATE|inotify.constants.IN_DELETE)

        rprint(INFO_LEADER + f"Listening on http://127.0.0.1:8000")
        rprint(INFO_LEADER + f"Watching {base_dir} directory for updates")
        
        for (header, type_names, path, filename) in i.event_gen(yield_nones=False):
            rprint(INFO_LEADER + f"Change detected in {path}/{filename}")
            debounced_run()


if __name__ == "__main__":
    fire.Fire(CLI)
