from __future__ import annotations

from typing import TYPE_CHECKING

from blends.stack.partial_path.partial_path import PartialPath
from blends.stack.partial_path.partial_stacks import (
    PartialScopedSymbol,
    PartialScopeStack,
    PartialSymbolStack,
)
from blends.stack.partial_path.variables import ScopeStackVariable, SymbolStackVariable

if TYPE_CHECKING:
    from blends.stack.partial_path_database import FileHandle
    from blends.stack.partial_path_db import PartialPathDb
    from blends.stack.view import StackGraphView

_BRIDGE_SYMBOL_VAR_ID = 1
_BRIDGE_SCOPE_ATTACHED_VAR_ID = 2
_BRIDGE_SCOPE_STACK_VAR_ID = 1


def _make_bridge_partial_path(
    start_node_index: int,
    pre_bound_symbol_id: int,
    post_bound_symbol_id: int,
    module_symbol_id: int,
) -> PartialPath:
    symbol_var = SymbolStackVariable(var_id=_BRIDGE_SYMBOL_VAR_ID)
    scope_attached_var = ScopeStackVariable(var_id=_BRIDGE_SCOPE_ATTACHED_VAR_ID)
    scope_stack_var = ScopeStackVariable(var_id=_BRIDGE_SCOPE_STACK_VAR_ID)

    pre_symbol_stack = PartialSymbolStack(
        symbols=(
            PartialScopedSymbol(
                symbol_id=pre_bound_symbol_id,
                scopes=PartialScopeStack.from_variable(scope_attached_var),
            ),
        ),
        variable=symbol_var,
    )
    post_symbol_stack = PartialSymbolStack(
        symbols=(
            PartialScopedSymbol(symbol_id=module_symbol_id, scopes=None),
            PartialScopedSymbol(
                symbol_id=post_bound_symbol_id,
                scopes=PartialScopeStack.from_variable(scope_attached_var),
            ),
        ),
        variable=symbol_var,
    )
    pre_scope_stack = PartialScopeStack.from_variable(scope_stack_var)
    post_scope_stack = PartialScopeStack.from_variable(scope_attached_var)

    return PartialPath(
        start_node_index=start_node_index,
        end_node_index=0,
        symbol_stack_precondition=pre_symbol_stack,
        symbol_stack_postcondition=post_symbol_stack,
        scope_stack_precondition=pre_scope_stack,
        scope_stack_postcondition=post_scope_stack,
        edges=(),
    )


def index_bridge_paths_for_file(
    view: StackGraphView,
    *,
    file_handle: FileHandle,
    db: PartialPathDb,
) -> None:
    for node_index, is_bridge in enumerate(view.node_is_import_binding):
        if not is_bridge:
            continue
        module_stem = view.node_import_module_stem[node_index]
        if not module_stem:
            continue
        module_symbol_id = db.symbols.symbol_to_id.get(module_stem)
        if module_symbol_id is None:
            continue
        pre_bound_symbol_id = view.node_symbol_id[node_index]
        if pre_bound_symbol_id is None:
            continue
        import_source_symbol = view.node_import_source_symbol[node_index]
        source_symbol_str = (
            import_source_symbol
            if import_source_symbol is not None
            else view.symbols.id_to_symbol[pre_bound_symbol_id]
        )
        post_bound_symbol_id = db.symbols.symbol_to_id.get(source_symbol_str)
        if post_bound_symbol_id is None:
            post_bound_symbol_id = db.symbols.intern(source_symbol_str)
        bridge = _make_bridge_partial_path(
            node_index, pre_bound_symbol_id, post_bound_symbol_id, module_symbol_id
        )
        db.add_bridge_path(file_handle, bridge)
