_config_cache = {}

def _load(filename, depfiles):
    from . import load_config
    if not filename in _config_cache:
        if filename.exists():
            depfiles.add(filename)
            data = load_config(filename)
            _config_cache[filename] = data
    return _config_cache.get(filename, dict())


def _build_config(chain, depfiles):
    config = {}
    for d in [_load(c, depfiles) for c in chain]:
        for k, v in d.items():
            if isinstance(v, (list, tuple)):
                config[k] = config.get(k, list()) + list(v)
            elif isinstance(v, dict):
                config[k] = config.get(k, dict())
                config[k].update(v)
            else:
                config[k] = v

    return config


def _make_ninja_config(outfile, config, files):
    from os import makedirs
    from ninja.ninja_syntax import Writer

    makedirs(outfile.parent, exist_ok=True)

    with open(outfile, "w") as buildfile:
        build = Writer(buildfile)
        build.comment("This file is automatically generated by bonnibel")
        build.comment("Source config files:")
        for f in files:
            build.comment(f"  - {f}")

        build.newline()
        for k, v in config.items():
            build.variable(k, v)

 
def generate_configs(root, output, config, targets, kinds):

    assets = root / "assets" / "build"
    base = ["global.yaml", f"config.{config}.yaml"]

    depfiles = set()

    for target in targets:
        chain = base + [f"target.{target}.yaml"]

        files = [assets / f for f in chain]
        config = _build_config(files, depfiles)
        outfile = output / target / f"config.ninja"
        _make_ninja_config(outfile, config, files)

        for kind in kinds:
            custom = [f"kind.{kind}.yaml", f"target.{target}.{kind}.yaml"]
            files = [assets / f for f in chain + custom]
            config = _build_config(files, depfiles)
            outfile = output / target / f"config.{kind}.ninja"
            _make_ninja_config(outfile, config, files)

    return depfiles