"""
TYPE_CONFUSION: Dynamic dispatch/type errors violating expected protocol.

Unsafe region: machine state where an operation receives values of incompatible
types that violate the expected type protocol, leading to TypeError.

This is a pure Python semantics bug class. Type confusion includes:
- Arithmetic operations on incompatible types (e.g., int + str)
- Comparisons on incompatible types (e.g., int < str in Python 3)
- Calling non-callable values
- Attribute access on values that don't support it
- Protocol violations (e.g., using a non-iterable in a for loop)

Distinguished from NULL_PTR: NULL_PTR is specifically None misuse.
TYPE_CONFUSION is broader: any type mismatch that causes TypeError.

The symbolic VM tracks type_confusion_reached when an operation's type_ok
condition is violated (but not due to None misuse).

GUARD INTEGRATION (barrier-certificate-theory.tex §10.3):
The unsafe region U_type_add is:
  U_type_add := { s | π == π_add ∧ (θ_x_int·θ_y_int == 0) }

If g_type(x, T) is established, type confusion involving x is SAFE for type T.
"""

from typing import Optional
import z3


def is_unsafe_type_confusion(state) -> bool:
    """
    Unsafe predicate U_TYPE_CONFUSION(σ).
    
    Returns True if the machine state σ has:
    - type_confusion_reached flag set to True, indicating an operation
      received incompatible types (excluding None misuse)
    - OR exception is "TypeError" without evidence of None misuse
    
    GUARD CHECK: If g_type guards are established for the operands,
    type confusion is considered safe.
    
    Note: This is distinguished from NULL_PTR. NULL_PTR captures None misuse
    specifically. TYPE_CONFUSION captures other type protocol violations.
    """
    # Check if type guards are established
    if hasattr(state, 'type_confusion_context') and state.type_confusion_context:
        operand_var = state.type_confusion_context.get('operand_var')
        expected_type = state.type_confusion_context.get('expected_type')
        if operand_var and expected_type and hasattr(state, 'has_type_guard'):
            if state.has_type_guard(operand_var, expected_type):
                # Guard established: operand was type-checked
                return False
    
    if hasattr(state, 'type_confusion_reached') and state.type_confusion_reached:
        return True
    
    # TypeError that isn't None misuse
    if state.exception == "TypeError":
        # If none_misuse_reached is True, this is NULL_PTR, not TYPE_CONFUSION
        if hasattr(state, 'none_misuse_reached') and state.none_misuse_reached:
            return False
        # Otherwise, it's a general type error (TYPE_CONFUSION)
        return True
    
    return False


def is_guarded_operation(state, operand_var: Optional[str] = None, expected_type: Optional[str] = None) -> bool:
    """
    Check if an operation is protected by a type guard.
    
    Returns True if g_type(operand_var, expected_type) is established.
    """
    if not hasattr(state, 'has_type_guard'):
        return False
    
    if operand_var and expected_type:
        return state.has_type_guard(operand_var, expected_type)
    
    # Check context if available
    if hasattr(state, 'type_confusion_context') and state.type_confusion_context:
        var = state.type_confusion_context.get('operand_var')
        typ = state.type_confusion_context.get('expected_type')
        if var and typ:
            return state.has_type_guard(var, typ)
    
    return False


def extract_counterexample(state, path_trace: list[str]) -> dict:
    """
    Extract a witness trace for TYPE_CONFUSION bug.
    
    Returns a dictionary with:
    - bug_type: "TYPE_CONFUSION"
    - trace: list of executed instructions
    - final_state: description of the unsafe state
    - path_condition: the Z3 path constraint (if available)
    - guard_info: information about type guards (NEW)
    """
    result = {
        "bug_type": "TYPE_CONFUSION",
        "trace": path_trace,
        "final_state": {
            "exception": state.exception,
            "type_confusion_reached": getattr(state, 'type_confusion_reached', False),
            "none_misuse_reached": getattr(state, 'none_misuse_reached', False),
            "last_operation": getattr(state, 'last_operation', None),
            "frame_count": len(state.frame_stack),
            "halted": state.halted
        },
        "path_condition": str(state.path_condition) if hasattr(state, 'path_condition') else None
    }
    
    # Include type confusion context if available
    if hasattr(state, 'type_confusion_context') and state.type_confusion_context:
        result['context'] = state.type_confusion_context
    
    # Include guard information
    if hasattr(state, 'established_guards'):
        type_guards = {k: v for k, v in state.established_guards.items() if k.startswith('type:')}
        if type_guards:
            result['guard_info'] = {
                'type_guards': type_guards,
                'guard_protected': is_guarded_operation(state)
            }
    
    return result
