"""
Find directories
"""
import importlib
import os
import sys
from typing import Any
from typing import Dict
from typing import Iterable
from typing import List

import dict_tools.update


def dir_list(
    subname: str, p_name: str, pypath: List[str] = None, static: List[str] = None
) -> List[str]:
    """
    Return the directories to look for modules in, pypath specifies files
    relative to an installed python package, static is for static dirs
    :param subname: ignored
    :param p_name: ignored
    :param pypath: One or many python paths which will be imported
    :param static: Directories that can be explicitly passed
    """
    ret = []
    for path in pypath:
        mod = importlib.import_module(path)
        for m_path in mod.__path__:
            # If we are inside of an executable the path will be different
            ret.append(m_path)
    ret.extend(static)
    return ret


def inline_dirs(dirs: Iterable[str], subdir: str) -> List[str]:
    """
    Look for the named subdir in the list of dirs
    :param dirs: The names of configured dynamic dirs
    :param subdir: The name of the subdir to check for in the list of dynamic dirs
    :return An extended list of dirs that includes the found subdirs
    """
    ret = []
    for dir_ in dirs:
        check = os.path.join(dir_, subdir)
        if os.path.isdir(check):
            ret.append(check)
    return ret


def dynamic_dirs() -> Dict[str, Any]:
    """
    Iterate over the available python package imports and look for configured
    dynamic dirs
    """
    dirs = []
    ret = {}
    for dir_ in sys.path:
        if not os.path.isdir(dir_):
            continue
        for sub in os.listdir(dir_):
            full = os.path.join(dir_, sub)
            if full.endswith(".egg-link"):
                with open(full) as rfh:
                    dirs.append(rfh.read().strip())
            if os.path.isdir(full):
                dirs.append(full)
    for dir_ in dirs:
        conf = os.path.join(dir_, "conf.py")
        context = {}
        if not os.path.isfile(conf):
            continue
        try:
            with open(conf) as f:
                code = f.read()
                if "DYNE" in code:
                    exec(code, context)
                else:
                    continue
        except Exception:
            continue
        if "DYNE" in context:
            if not isinstance(context["DYNE"], dict):
                continue
            for name, paths in context["DYNE"].items():
                if not isinstance(paths, list):
                    continue
                if name not in ret:
                    ret[name] = {
                        "paths": [],
                        "CONFIG": {},
                        "CLI_CONFIG": {},
                        "SUBCOMMANDS": {},
                    }
                if "CONFIG" in context:
                    dict_tools.update.update(ret[name]["CONFIG"], context["CONFIG"])
                if "CLI_CONFIG" in context:
                    dict_tools.update.update(
                        ret[name]["CLI_CONFIG"], context["CLI_CONFIG"]
                    )
                if "SUBCOMMANDS" in context:
                    dict_tools.update.update(
                        ret[name]["SUBCOMMANDS"], context["SUBCOMMANDS"]
                    )
                for path in paths:
                    ref = os.path.join(dir_, path.replace(".", os.sep))
                    if dir_.endswith(name):
                        ret[name]["paths"].insert(0, ref)
                    else:
                        ret[name]["paths"].append(ref)
    for name in ret:
        if not ret[name]:
            continue
        first = ret[name]["paths"].pop(0)
        ret[name]["paths"] = sorted(ret[name]["paths"])
        ret[name]["paths"].insert(0, first)
    return ret
