from __future__ import annotations

import time
from typing import TYPE_CHECKING

from blends.stack.stacks import (
    ScopeStackNode,
    StackState,
    SymbolStackNode,
)

if TYPE_CHECKING:
    from blends.stack.forward_stitcher import ForwardStitcherConfig
    from blends.stack.partial_path import (
        PartialPath,
        PartialScopeStack,
        PartialSymbolStack,
    )


def _path_priority(path: PartialPath) -> int:
    symbol_depth = len(path.symbol_stack_postcondition.symbols)
    scope_depth = len(path.scope_stack_postcondition.scopes)

    variable_penalty = 0
    if path.symbol_stack_postcondition.variable is not None:
        variable_penalty += 1
    if path.scope_stack_postcondition.variable is not None:
        variable_penalty += 1

    return symbol_depth + scope_depth + variable_penalty


def _should_cancel(config: ForwardStitcherConfig) -> bool:
    if config.is_cancelled is not None and config.is_cancelled():
        return True
    return _deadline_exceeded(config)


def _deadline_exceeded(config: ForwardStitcherConfig) -> bool:
    if config.deadline is None:
        return False
    return time.monotonic() >= config.deadline


def _stack_state_from_partial(
    symbol_stack: PartialSymbolStack, scope_stack: PartialScopeStack
) -> StackState:
    symbol_node = None
    scope_node = None
    if not symbol_stack.can_match_empty():
        symbol_node = SymbolStackNode(symbol_id=0, scopes=None, tail=None)
    if not scope_stack.can_match_empty():
        scope_node = ScopeStackNode(scope_index=0, tail=None)
    return StackState(symbol_stack=symbol_node, scope_stack=scope_node)
