# processors/process_call.py
# -*- coding: utf-8 -*-
import sympy
import traceback
# Asumiendo que estas funciones ahora existen y están adaptadas
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, format_variable_name, get_target_scl_name
from .symbol_manager import SymbolManager # Necesitamos pasar el symbol_manager

# Definir sufijo globalmente o importar
SCL_SUFFIX = "_sympy_processed"

def process_call(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
    instr_uid = instruction["instruction_uid"]
    instr_type_original = instruction.get("type", "") # Tipo antes de añadir sufijo
    if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
        return False

    block_name = instruction.get("block_name", f"UnknownCall_{instr_uid}")
    block_type = instruction.get("block_type")  # FC, FB
    instance_db = instruction.get("instance_db")  # Nombre del DB de instancia (para FB)

    # Formatear nombres SCL (para la llamada final)
    block_name_scl = format_variable_name(block_name)
    instance_db_scl = format_variable_name(instance_db) if instance_db else None

    # --- Manejo de EN ---
    en_input = instruction["inputs"].get("en")
    sympy_en_expr = get_sympy_representation(en_input, network_id, sympy_map, symbol_manager) if en_input else sympy.true

    if sympy_en_expr is None:
        # print(f"DEBUG Call {instr_uid}: EN dependency not ready.")
        return False # Dependencia EN no resuelta

    # --- Procesar Parámetros de Entrada ---
    scl_call_params = []
    processed_inputs = {"en"}
    dependencies_resolved = True

    # Ordenar para consistencia
    input_pin_names = sorted(instruction.get("inputs", {}).keys())

    for pin_name in input_pin_names:
        if pin_name not in processed_inputs:
            source_info = instruction["inputs"][pin_name]
            # Obtener la representación de la fuente (puede ser SymPy o Constante/String)
            source_sympy_or_const = get_sympy_representation(source_info, network_id, sympy_map, symbol_manager)

            if source_sympy_or_const is None:
                # print(f"DEBUG Call {instr_uid}: Input param '{pin_name}' dependency not ready.")
                dependencies_resolved = False
                break # Salir si una dependencia no está lista

            # Convertir la expresión/constante a SCL para la llamada
            # Detectar si es una dirección indirecta (comienza con %)
            is_address_ref = isinstance(source_sympy_or_const, str) and source_sympy_or_const.startswith("%")
            
            # El nombre del pin SÍ necesita formateo
            pin_name_scl = format_variable_name(pin_name)
            
            # Para direcciones indirectas, usar => en lugar de :=
            if is_address_ref:
                # Es un parámetro InOut con dirección indirecta
                scl_call_params.append(f"{pin_name_scl} => {source_sympy_or_const}")
            else:
                # Es un parámetro normal (In)
                param_scl_value = sympy_expr_to_scl(source_sympy_or_const, symbol_manager)
                scl_call_params.append(f"{pin_name_scl} := {param_scl_value}")
                
            processed_inputs.add(pin_name)

    if not dependencies_resolved:
        return False

    # --- Construcción de la Llamada SCL (similar a antes) ---
    scl_call_body = ""
    param_string = ", ".join(scl_call_params)

    if block_type == "FB":
        if not instance_db_scl:
            print(f"Error: Call FB '{block_name_scl}' (UID {instr_uid}) sin instancia.")
            instruction["scl"] = f"// ERROR: FB Call {block_name_scl} sin instancia"
            instruction["type"] = f"Call_FB_error"
            return True
        scl_call_body = f"{instance_db_scl}({param_string});"
    elif block_type == "FC":
        scl_call_body = f"{block_name_scl}({param_string});"
    else:
        print(f"Advertencia: Tipo de bloque no soportado para Call UID {instr_uid}: {block_type}")
        scl_call_body = f"// ERROR: Call a bloque tipo '{block_type}' no soportado: {block_name_scl}"
        instruction["type"] = f"Call_{block_type}_error" # Marcar como error

    # --- Aplicar Condición EN (usando la expresión SymPy EN) ---
    scl_final = ""
    if sympy_en_expr != sympy.true:
        # Simplificar la condición EN ANTES de convertirla a SCL
        try:
            #simplified_en_expr = sympy.simplify_logic(sympy_en_expr, force=True)
            simplified_en_expr = sympy.logic.boolalg.to_dnf(sympy_en_expr, simplify=True)
        except Exception as e:
            print(f"Error simplifying EN for Call {instr_uid}: {e}")
            simplified_en_expr = sympy_en_expr # Fallback
        en_condition_scl = sympy_expr_to_scl(simplified_en_expr, symbol_manager)

        indented_call = "\n".join([f"  {line}" for line in scl_call_body.splitlines()])
        scl_final = f"IF {en_condition_scl} THEN\n{indented_call}\nEND_IF;"
    else:
        scl_final = scl_call_body

    # --- Actualizar Instrucción y Mapa SymPy ---
    instruction["scl"] = scl_final # Guardar el SCL final generado
    instruction["type"] = (f"Call_{block_type}{SCL_SUFFIX}" if "_error" not in instruction["type"] else instruction["type"])

    # Actualizar sympy_map con el estado ENO (es la expresión SymPy de EN)
    map_key_eno = (network_id, instr_uid, "eno")
    sympy_map[map_key_eno] = sympy_en_expr # Guardar la expresión SymPy para ENO

    # Propagar valores de salida (requiere info de interfaz o heurística)
    # Si se sabe que hay una salida 'MyOutput', se podría añadir su SCL al mapa
    # Ejemplo MUY simplificado:
    # for pin_name, dest_list in instruction.get("outputs", {}).items():
    #      if pin_name != 'eno' and dest_list: # Asumir que hay un destino
    #         map_key_out = (network_id, instr_uid, pin_name)
    #         if block_type == "FB" and instance_db_scl:
    #             sympy_map[map_key_out] = f"{instance_db_scl}.{format_variable_name(pin_name)}" # Guardar el *string* de acceso SCL
    #         # Para FCs es más complejo, necesitaría asignación explícita a temp
    #         # else: # FC output -> necesita temp var
    #         #    temp_var = generate_temp_var_name(...)
    #         #    sympy_map[map_key_out] = temp_var

    return True

# --- Processor Information Function ---
def get_processor_info():
    """Devuelve la información para las llamadas a FC y FB."""
    return [
        {'type_name': 'call_fc', 'processor_func': process_call, 'priority': 6},
        {'type_name': 'call_fb', 'processor_func': process_call, 'priority': 6}
    ]