from . import cfg
from .shared import stack_add_res
from . import (
    __version__,
    autoscaling,
    cloudformation,
    cloudfront,
    ec2,
    ecr,
    ecs,
    efs,
    iam,
    joker,
    elasticloadbalancing,
    mappings,
    rds,
    s3,
    waf,
)


def execute_method(RP_cmm):
    processed = []

    def _process(k, v):
        func_name = v["func"]
        module_name = v["module"]
        module = globals()[module_name]
        dep = v.get("dep", [])

        if k in list(RP_cmm.keys()):
            # process dependency modules first
            for m in dep:
                if m in list(RP_cmm.keys()) and m not in processed:
                    _process(m, cfg.CFG_TO_FUNC[m])
                    processed.append(m)

            RP_value = RP_cmm[k]
            if isinstance(RP_value, str) and RP_value == "IBOX_SKIP_FUNC":
                return
            if isinstance(func_name, list):
                for n in func_name:
                    getattr(module, n)(key=k)
                return
            stacktype_func = f"{func_name}{cfg.stacktype.upper()}"
            if stacktype_func in dir(module):
                getattr(module, stacktype_func)(key=k)
            elif func_name in dir(module):
                getattr(module, func_name)(key=k)
            elif module_name == "joker":
                # for resources that can be built using only auto_get_props
                joker.Joker(key=k, module=func_name[0], cls=func_name[1])
            processed.append(k)

    for k, v in cfg.CFG_TO_FUNC.items():
        # skip already processed keys
        if k in processed:
            continue
        _process(k, v)

    stack_add_res()


def generate():
    try:
        execute_method(cfg.RP_tree)
    except Exception:
        # in case of error call stack_add_res to empty the cfg Parameters
        # Conditions Mappings Resources Outputs  dicts. This is needed cause
        # get_template "restore base cfg" section do not recursive remove
        # "sub-objetcs" or to say it in a better way:
        # dict clear methods reset the contents,
        # but all references to the same instance will still be present.
        stack_add_res()
        raise

    version_text = f"(Generated by awsibox >= {__version__})"
    cfg.template.set_description(f"{cfg.envrole} {version_text} [{cfg.stacktype}]")
    cfg.template.set_version("2010-09-09")

    return cfg.template
