import argparse
import os.path
import sys
from pathlib import Path
from typing import List, Union

from jinja2 import Environment, PackageLoader, select_autoescape

from ee.kicad import read_schematics
from ee.project import Project


def ninja_path_filter(s: Union[Path, str, List[str]]) -> str:
    if isinstance(s, Path):
        s = str(s)

    if isinstance(s, str):
        return s. \
            replace("$", "$$"). \
            replace(" ", "$ ")
    elif isinstance(s, list):

        if len(s) == 1:
            return ninja_path_filter(s[0])

        return "$\n" + " $\n".join(["  " + ninja_path_filter(path) for path in s])
    else:
        raise Exception("Unsupported argument type: {}".format(type(s)))


def parent_dir_filter(s: Union[str, Path]) -> Path:
    return Path(s).parent


def basename_filter(s: Union[str, Path]) -> str:
    return os.path.basename(str(s))


def noext_filter(s: Union[str, Path]) -> str:
    return os.path.splitext(os.path.basename(str(s)))[0]


def generate(project: Project):
    def _create_env():
        e = Environment(
            loader=PackageLoader(__name__, "templates"),
            autoescape=select_autoescape(["html", "xml"]),
            keep_trailing_newline=True,
        )
        e.filters["ninja_path"] = ninja_path_filter
        e.filters["parent_dir"] = parent_dir_filter
        e.filters["basename"] = basename_filter
        e.filters["noext"] = noext_filter
        return e

    part_dbs = []
    params = {
        "ee": "{} -m ee".format(os.path.relpath(sys.executable, Path("."))),
        "project": project,
        "part_dbs": part_dbs,
    }

    gerber_zip = None

    if project.cfg.has_section("kicad-project"):
        kp = project.cfg["kicad-project"]
        if "sch" in kp:
            sch_path = Path(project.cfg["kicad-project"]["sch"])
            sch = read_schematics(str(sch_path))

            sch_files = sorted([s.path for s in sch.schematics])

            params["sch"] = sch_path
            params["sch_files"] = sch_files

        if "pcb" in kp:
            params["pcb"] = Path(project.cfg["kicad-project"]["pcb"])
            gerber_zip = "prod/gerber.zip"

    # TODO: read from config
    distributors = ["digikey"]
    params["distributors"] = distributors

    if gerber_zip is not None:
        params["gerber_zip"] = gerber_zip

    # ee_dir = sch_path.parent / "ee"
    build_ninja = project.project_dir / "build.ninja"

    parts_yaml_files = [path for path in project.project_dir.iterdir() if str(path).endswith("-parts.yaml")]
    params["parts_yaml_files"] = parts_yaml_files

    # Local part databases first
    part_dbs.extend([parent_dir_filter(p) / noext_filter(p) for p in parts_yaml_files])
    part_dbs.extend([Path("ee") / d / "parts" for d in distributors])

    with build_ninja.open("w") as f:
        env = _create_env()
        template = env.get_template("build.ninja.j2")
        f.write(template.render(**params))


parser = argparse.ArgumentParser()

args = parser.parse_args()

generate(Project.load())