# processors/process_se.py
# -*- coding: utf-8 -*-
import sympy
import traceback
# Usar las nuevas utilidades
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, format_variable_name, get_target_scl_name
from .symbol_manager import SymbolManager, extract_plc_variable_name

SCL_SUFFIX = "_sympy_processed"

def process_se(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
    """
    Genera SCL para Temporizador de Pulso (Se -> TP) o SdCoil (-> TON).
    Usa SymPy para entradas y almacena Symbol para salida Q.
    """
    instr_uid = instruction["instruction_uid"]
    # Obtener tipo original (antes de añadir sufijo) para determinar comportamiento
    instr_type_original = instruction.get("type", "").replace(SCL_SUFFIX,"").replace("_error","") # Se o SdCoil
    current_type = instruction.get("type","") # Tipo actual para chequeo inicial
    if current_type.endswith(SCL_SUFFIX) or "_error" in current_type:
        return False

    # Determinar el tipo de instrucción SCL y pines de entrada/salida correctos
    scl_timer_type = "TP"
    pin_in = "s"        # Pin de entrada para Se
    pin_time = "tv"     # Pin de valor de tiempo para Se
    pin_instance = "timer" # Pin donde se conecta la instancia para Se
    pin_out_q = "q"     # Pin de salida Q para Se
    pin_out_time = "rt" # Pin de tiempo restante para Se -> TP.ET

    # Ajustar pines si el tipo original era SdCoil
    if instr_type_original == "SdCoil":
        scl_timer_type = "TON" # SdCoil es funcionalmente un TON
        pin_in = "in"          # SdCoil usa 'in'
        pin_time = "value"     # SdCoil usa 'value'
        pin_instance = "operand" # SdCoil usa 'operand' como instancia/variable de salida
        pin_out_q = "out"      # SdCoil usa 'out' como pin de salida Q
        pin_out_time = None    # SdCoil no tiene salida ET explícita

    # 1. Obtener Inputs usando los nombres de pin correctos
    s_info = instruction["inputs"].get(pin_in)
    tv_info = instruction["inputs"].get(pin_time)
    timer_instance_info = instruction["inputs"].get(pin_instance)

    # Obtener representaciones (SymPy o Constante/String)
    sympy_s_expr = get_sympy_representation(s_info, network_id, sympy_map, symbol_manager)
    sympy_or_const_tv = get_sympy_representation(tv_info, network_id, sympy_map, symbol_manager)
    # Obtener el nombre PLC original de la INSTANCIA
    instance_plc_name = extract_plc_variable_name(timer_instance_info)

    # 2. Verificar dependencias
    if sympy_s_expr is None or sympy_or_const_tv is None:
        # print(f"DEBUG {instr_type_original} {instr_uid}: Input/TV dependency not ready")
        return False
    if instance_plc_name is None:
        print(f"Error: {instr_type_original} {instr_uid} sin variable de instancia en pin '{pin_instance}'.")
        instance_plc_name = f"#{scl_timer_type}_INSTANCE_{instr_uid}" # Placeholder
        print(f"Advertencia: Usando placeholder '{instance_plc_name}'. ¡Declarar en SCL!")

    # 3. Formatear nombre de instancia para SCL
    instance_name_scl = format_variable_name(instance_plc_name)

    # 4. Convertir entradas SymPy/Constante a SCL strings (simplificando la entrada IN)
    try:
        # Simplificar la expresión de entrada booleana
        simplified_s_expr = sympy.simplify_logic(sympy_s_expr, force=True)
        simplified_s_expr = sympy.logic.boolalg.to_dnf(sympy_s_expr, simplify=True)
    except Exception as e:
        print(f"Error simplifying '{pin_in}' input for {instr_type_original} {instr_uid}: {e}")
        simplified_s_expr = sympy_s_expr # Fallback
    s_scl = sympy_expr_to_scl(simplified_s_expr, symbol_manager)

    # tv normalmente es constante, sympy_expr_to_scl debería manejarlo
    tv_scl = sympy_expr_to_scl(sympy_or_const_tv, symbol_manager)

    # 5. Generar la llamada SCL
    # Ignoramos 'r' (reset) de Se si existiera
    scl_call = f"{instance_name_scl}(IN := {s_scl}, PT := {tv_scl}); // TODO: Declarar {instance_name_scl} : {scl_timer_type};"

    # 6. Actualizar instrucción con el SCL final
    instruction["scl"] = scl_call
    instruction["type"] = instr_type_original + SCL_SUFFIX # Marcar como procesado

    # 7. Actualizar sympy_map para las salidas (Q y ET si aplica)
    # Usar los nombres de pin originales determinados al principio
    map_key_q = (network_id, instr_uid, pin_out_q) # pin_out_q es 'q' o 'out'
    q_output_scl_access = f"{instance_name_scl}.Q" # Siempre accedemos a .Q del FB SCL
    # *** OBTENER/CREAR Y ALMACENAR SYMBOL para la salida booleana Q ***
    sympy_q_symbol = symbol_manager.get_symbol(q_output_scl_access)
    if sympy_q_symbol:
        sympy_map[map_key_q] = sympy_q_symbol # Almacenar el OBJETO SYMBOL
    else:
        # Manejar error si no se pudo crear el símbolo
        print(f"Error: No se pudo crear símbolo para {q_output_scl_access} en {instr_type_original} {instr_uid}")
        sympy_map[map_key_q] = None # Indicar error/irresoluble

    # Almacenar ET solo si corresponde (para Se, no para SdCoil)
    if pin_out_time: # pin_out_time es 'rt' o None
        map_key_rt = (network_id, instr_uid, pin_out_time)
        # ET es TIME, no booleano. Almacenar el string SCL de acceso está bien.
        sympy_map[map_key_rt] = f"{instance_name_scl}.ET" # Salida ET del FB SCL

    return True

# --- Processor Information Function ---
def get_processor_info():
    """Devuelve la info para Se (-> TP) y SdCoil (-> TON, manejado aquí)."""
    return [
        {'type_name': 'se', 'processor_func': process_se, 'priority': 5},
        # Asegurarse que x1.py mapea SdCoil a este procesador o a uno específico
        {'type_name': 'sdcoil', 'processor_func': process_se, 'priority': 5}
    ]