from blends.ctx import ctx
from blends.models import (
    NId,
)
from blends.stack.edges import (
    Edge,
    add_edge,
)
from blends.stack.node_helpers import (
    pop_scoped_symbol_node_attributes,
)
from blends.syntax.builders.utils import (
    add_pattern_binding_nodes,
    bound_identifier_symbol,
    get_next_binding_precedence,
)
from blends.syntax.models import (
    SyntaxGraphArgs,
)


def build_for_statement_node(
    args: SyntaxGraphArgs,
    initializer_node: NId | None,
    condition_node: NId | None,
    update_node: NId | None,
    body_node: NId,
) -> NId:
    args.syntax_graph.add_node(
        args.n_id,
        label_type="ForStatement",
        block_id=body_node,
    )

    args.syntax_graph.add_edge(
        args.n_id,
        args.generic(args.fork_n_id(body_node)),
        label_ast="AST",
    )

    if initializer_node:
        args.syntax_graph.update_node_attribute(args.n_id, "initializer_id", initializer_node)
        args.syntax_graph.add_edge(
            args.n_id,
            args.generic(args.fork_n_id(initializer_node)),
            label_ast="AST",
        )

    if condition_node:
        args.syntax_graph.update_node_attribute(args.n_id, "condition_id", condition_node)
        args.syntax_graph.add_edge(
            args.n_id,
            args.generic(args.fork_n_id(condition_node)),
            label_ast="AST",
        )

    if update_node:
        args.syntax_graph.update_node_attribute(args.n_id, "update_id", update_node)
        args.syntax_graph.add_edge(
            args.n_id,
            args.generic(args.fork_n_id(update_node)),
            label_ast="AST",
        )

    if ctx.has_feature_flag("StackGraph") and initializer_node is not None:
        if (symbol := bound_identifier_symbol(args, var_id=initializer_node)) is not None:
            precedence = get_next_binding_precedence(args)
            args.syntax_graph.update_node(
                args.n_id,
                pop_scoped_symbol_node_attributes(
                    symbol=symbol,
                    precedence=precedence,
                ),
            )
            scope_stack = args.metadata.setdefault("scope_stack", [])
            if scope_stack and (parent_scope := scope_stack[-1]):
                add_edge(
                    args.syntax_graph,
                    Edge(source=parent_scope, sink=args.n_id, precedence=precedence),
                )
        else:
            add_pattern_binding_nodes(args, var_id=initializer_node)

    return args.n_id
