# iterate source tree
#   create directors in target tree
#   for each item:
#    run processor(s) on item, each processor could be in a chain or a branch
#    Processors also provide filename munging
#    output target based on processor output

import argparse
import logging
import os
import shutil
import sys
import time
from typing import Dict, List, cast

from .metadata import MetaTree
from .processchain import ProcessorChains
from .processors.processors import PassthroughException
from .pygments import pygments_get_css, pygments_markup_contents_html
from .template_tools import (date_iso8601, file_content, file_list,
                             file_list_hier, file_metadata, file_name,
                             file_raw, time_iso8601)

logger = logging.getLogger()


def setup_logging(verbose: bool = False) -> None:
    pass


def get_args(args: List[str]) -> argparse.Namespace:
    parser = argparse.ArgumentParser("Compile a Pixywerk directory into an output directory.")

    parser.add_argument("root", help="The root of the pixywerk directory to process.")
    parser.add_argument("output", help="The output directory to export post-compiled files to.")

    parser.add_argument(
        "-c", "--clean", help="Remove the target tree before proceeding (by renaming to .bak).", action="store_true"
    )
    parser.add_argument("-s", "--safe", help="Abort if the target directory already exists.", action="store_true")
    parser.add_argument("-t", "--template", help="The template directory (default: root/templates)", default=None)
    parser.add_argument("-d", "--dry-run", help="Perform a dry-run.", action="store_true")
    parser.add_argument("-v", "--verbose", help="Output verbosely.", action="store_true")
    parser.add_argument("--processors", help="Specify a path to a processor configuration file.", default=None)
    # parser.add_argument("--prescript", help="Specify one or more prescripts to run (in order specified) with context of the compile.", default=[], action="append")
    # parser.add_argument("--postscript", help="Specify one or more postsscripts to run (in order specified) with context of the compile.", default=[], action="append")
    result = parser.parse_args(args)

    # validate arguments
    if not os.path.isdir(result.root):
        raise FileNotFoundError("can't find root folder {}".format(result.root))

    if not result.template:
        result.template = os.path.join(result.root, "templates")
        result.excludes = [result.template]

    return result


def main() -> int:
    try:
        args = get_args(sys.argv[1:])
    except FileNotFoundError as ex:
        print("error finding arguments: {}".format(ex))
        return 1
    setup_logging(args.verbose)
    if os.path.exists(args.output) and args.clean:
        bak = "{}.bak-{}".format(args.output, int(time.time()))
        print("cleaning target {} -> {}".format(args.output, bak))
        os.rename(args.output, bak)

    process_chains = ProcessorChains(args.processors)

    default_metadata = {
        "templates": args.template,
        "template": "default.jinja2",
        "dir-template": "default-dir.jinja2",
        "filters": {},
        "build-time": time.time(),
        "uuid-oid-root": "pixywerk",
        "summary": "",
        "description": "",
        "author": "",
        "author_email": "",
    }
    meta_tree = MetaTree(args.root, default_metadata)
    file_list_cache = cast(Dict, {})
    file_cont_cache = cast(Dict, {})
    file_name_cache = cast(Dict, {})
    file_raw_cache = cast(Dict, {})
    flist = file_list(args.root, file_list_cache)
    default_metadata["globals"] = {
        "get_file_list": flist,
        "get_hier": file_list_hier(args.root, flist),
        "get_file_name": file_name(args.root, meta_tree, process_chains, file_name_cache),
        "get_file_content": file_content(args.root, meta_tree, process_chains, file_cont_cache),
        "get_raw": file_raw(args.root, file_raw_cache),
        "get_file_metadata": file_metadata(meta_tree),
        "get_time_iso8601": time_iso8601("UTC"),
        "get_date_iso8601": date_iso8601("UTC"),
        "pygments_get_css": pygments_get_css,
        "pygments_markup_contents_html": pygments_markup_contents_html,
    }

    for root, _, files in os.walk(args.root):
        workroot = os.path.relpath(root, args.root)
        if workroot == ".":
            workroot = ""
        target_dir = os.path.join(args.output, workroot)
        print("mkdir -> {}".format(target_dir))
        if not args.dry_run:
            try:
                os.mkdir(target_dir)
            except FileExistsError:
                if args.safe:
                    print("error, target directory exists, aborting")
                    return 1
        for f in files:
            # fixme global generic filters
            if f.endswith(".meta") or f.endswith("~"):
                continue
            metadata = meta_tree.get_metadata(os.path.join(workroot, f))
            chain = process_chains.get_chain_for_filename(os.path.join(root, f), ctx=metadata)
            print("process {} -> {}".format(os.path.join(root, f), os.path.join(target_dir, chain.output_filename)))
            if not args.dry_run:
                try:
                    with open(os.path.join(target_dir, chain.output_filename), "w") as outfile:
                        for line in chain.output:
                            outfile.write(line)
                except PassthroughException:
                    shutil.copyfile(os.path.join(root, f), os.path.join(target_dir, chain.output_filename))

    return 0


if __name__ == "__main__":
    sys.exit(main())
