from blends.ctx import ctx
from blends.models import (
    NId,
)
from blends.stack.edges import (
    Edge,
    add_edge,
)
from blends.stack.node_helpers import (
    import_binding_node_attributes,
)
from blends.syntax.builders.import_reference_chain import (
    build_import_reference_chain_to_root,
    normalize_module_path,
)
from blends.syntax.builders.utils import (
    get_next_binding_precedence,
)
from blends.syntax.models import (
    SyntaxGraphArgs,
)


def _bound_import_symbol(*, expression: str, alias: str | None) -> str:
    if isinstance(alias, str) and alias:
        return alias
    parts = expression.split(".")
    return parts[-1] if parts else expression


def build_import_module_node(
    args: SyntaxGraphArgs,
    expression: str,
    alias: str | None = None,
    module_path: str | None = None,
) -> NId:
    args.syntax_graph.add_node(
        args.n_id,
        expression=expression,
        label_type="ModuleImport",
    )

    if alias:
        args.syntax_graph.update_node_attribute(args.n_id, "label_alias", alias)

    if (bound := _bound_import_symbol(expression=expression, alias=alias)) and (
        scope_stack := args.metadata.get("scope_stack")
    ):
        args.syntax_graph.symbol_index.setdefault(bound, {}).setdefault(scope_stack[-1], []).append(
            args.n_id
        )

    if ctx.has_feature_flag("StackGraph"):
        bound = _bound_import_symbol(expression=expression, alias=alias)
        if bound and args.stack_graph is not None:
            precedence = get_next_binding_precedence(args)
            module_stem = (
                normalize_module_path(module_path)
                if module_path is not None
                else normalize_module_path(expression)
            )
            source_symbol = expression.rsplit(".", maxsplit=1)[-1] if alias else None
            import_attrs = import_binding_node_attributes(
                symbol=bound,
                precedence=precedence,
                import_module_stem=module_stem,
                import_source_symbol=source_symbol,
            )
            args.stack_graph.add_node(args.n_id, **import_attrs)
            scope_stack = args.metadata.setdefault("scope_stack", [])
            if scope_stack and (parent_scope := scope_stack[-1]):
                edge = Edge(source=parent_scope, sink=args.n_id, precedence=precedence)
                add_edge(args.stack_graph, edge)
            build_import_reference_chain_to_root(args, module_stem, args.n_id)

    return args.n_id
