# processors/process_edge_detector.py
# -*- coding: utf-8 -*-
import sympy
import traceback
from .processor_utils import get_sympy_representation, sympy_expr_to_scl, format_variable_name
from .symbol_manager import SymbolManager, extract_plc_variable_name

SCL_SUFFIX = "_sympy_processed"

def process_edge_detector(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
    """
    Genera la expresión SymPy para el pulso de PBox (P_TRIG) o NBox (N_TRIG).
    Guarda la expresión SymPy del pulso en sympy_map['out'].
    Genera y guarda el SCL para la actualización de memoria en '_edge_mem_update_scl'.
    El campo 'scl' principal se deja casi vacío/comentario.
    """
    instr_uid = instruction["instruction_uid"]
    instr_type_original = instruction.get("type", "") # PBox o NBox
    if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
        return False

    # 1. Obtener CLK (como SymPy expr) y MemBit (como SymPy Symbol)
    clk_input = instruction["inputs"].get("in")
    mem_bit_input = instruction["inputs"].get("bit")

    sympy_clk_expr = get_sympy_representation(clk_input, network_id, sympy_map, symbol_manager)
    mem_bit_plc_name = extract_plc_variable_name(mem_bit_input)
    sympy_mem_bit_symbol = symbol_manager.get_symbol(mem_bit_plc_name) if mem_bit_plc_name else None

    # 2. Verificar dependencias
    if sympy_clk_expr is None: return False
    if sympy_mem_bit_symbol is None:
        err_msg = f"MemBit no resuelto o no es variable para {instr_type_original} UID {instr_uid}"
        print(f"Error: {err_msg}")
        instruction["scl"] = f"// ERROR: {err_msg}"
        instruction["type"] = instr_type_original + "_error"
        return True

    # 3. Generar Lógica SymPy del *pulso*
    result_pulse_sympy_expr = sympy.false # Default
    scl_comment_prefix = ""
    if instr_type_original.upper() == "PBOX": # P_TRIG
        result_pulse_sympy_expr = sympy.And(sympy_clk_expr, sympy.Not(sympy_mem_bit_symbol))
        scl_comment_prefix = "P_TRIG"
    elif instr_type_original.upper() == "NBOX": # N_TRIG
        result_pulse_sympy_expr = sympy.And(sympy.Not(sympy_clk_expr), sympy_mem_bit_symbol)
        scl_comment_prefix = "N_TRIG"
    else: # Error
        instruction["scl"] = f"// ERROR: Tipo de flanco inesperado {instr_type_original}"
        instruction["type"] = instr_type_original + "_error"
        return True

    # 4. Generar el SCL para la actualización del bit de memoria
    # Necesitamos la representación SCL de la entrada CLK
    clk_scl_str = sympy_expr_to_scl(sympy_clk_expr, symbol_manager)
    # Usamos el nombre PLC original formateado para el bit de memoria
    mem_bit_scl_name = format_variable_name(mem_bit_plc_name)
    scl_mem_update = f"{mem_bit_scl_name} := {clk_scl_str};"
    scl_comment_for_update = f"// {scl_comment_prefix}({clk_scl_str}) - Mem: {mem_bit_scl_name}"

    # 5. Almacenar Resultados
    map_key_out = (network_id, instr_uid, "out")
    sympy_map[map_key_out] = result_pulse_sympy_expr # Guardar EXPRESIÓN SymPy del pulso

    # Guardar SCL de actualización + Comentario en campo temporal
    instruction['_edge_mem_update_scl'] = f"{scl_mem_update} {scl_comment_for_update}"

    # Marcar como procesado, SCL principal es solo comentario
    instruction['scl'] = f"// {instr_type_original} SymPy processed, logic in consumer"
    instruction["type"] = instr_type_original + SCL_SUFFIX

    # 6. Propagar ENO (es la expresión SymPy de CLK)
    map_key_eno = (network_id, instr_uid, "eno")
    sympy_map[map_key_eno] = sympy_clk_expr

    return True


# --- Processor Information Function ---
def get_processor_info():
    """Devuelve la info para los detectores de flanco PBox y NBox."""
    return [
        {'type_name': 'pbox', 'processor_func': process_edge_detector, 'priority': 2},
        {'type_name': 'nbox', 'processor_func': process_edge_detector, 'priority': 2}
    ]