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

SCL_SUFFIX = "_sympy_processed"

def process_counter(instruction, network_id, sympy_map, symbol_manager: SymbolManager, data):
    """
    Genera SCL para Contadores (CTU, CTD, CTUD).
    Requiere datos de instancia (DB o STAT).
    """
    instr_uid = instruction["instruction_uid"]
    instr_type_original = instruction.get("type", "") # CTU, CTD, CTUD
    if instr_type_original.endswith(SCL_SUFFIX) or "_error" in instr_type_original:
        return False

    # 1. Definir pines de entrada esperados
    input_pins_map = {
        "CTU": ["CU", "R", "PV"],
        "CTD": ["CD", "LD", "PV"],
        "CTUD": ["CU", "CD", "R", "LD", "PV"]
    }
    input_pins = input_pins_map.get(instr_type_original.upper())
    if not input_pins:
        instruction["scl"] = f"// ERROR: Tipo de contador no soportado: {instr_type_original}"
        instruction["type"] = instr_type_original + "_error"
        return True

    # 2. Procesar Parámetros de Entrada
    scl_call_params = []
    dependencies_resolved = True
    optional_pins = {"R", "LD"} # Estos pueden no estar conectados

    for pin in input_pins:
        pin_info = instruction["inputs"].get(pin)
        if pin_info: # Si el pin está definido en el JSON
            source_sympy_or_const = get_sympy_representation(pin_info, network_id, sympy_map, symbol_manager)
            if source_sympy_or_const is None:
                # print(f"DEBUG Counter {instr_uid}: Input param '{pin}' dependency not ready.")
                dependencies_resolved = False
                break
            # Convertir a SCL para la llamada (sin simplificar aquí)
            param_scl_value = sympy_expr_to_scl(source_sympy_or_const, symbol_manager)
            pin_name_scl = format_variable_name(pin) # Formatear nombre del parámetro
            scl_call_params.append(f"{pin_name_scl} := {param_scl_value}")
        elif pin not in optional_pins: # Si falta un pin requerido
            print(f"Error: Falta entrada requerida '{pin}' para {instr_type_original} UID {instr_uid}.")
            instruction["scl"] = f"// ERROR: Falta entrada requerida '{pin}' para {instr_type_original} UID {instr_uid}."
            instruction["type"] = instr_type_original + "_error"
            return True

    if not dependencies_resolved:
        return False

    # 3. Obtener Nombre de Instancia
    # Asumiendo que x1 o una fase previa llena 'instance_db' si es un FB multi-instancia
    instance_name_raw = instruction.get("instance_db")
    if not instance_name_raw:
        # Asumiendo que es STAT si no hay DB instancia explícito (requiere declaración en x3)
        instance_name_raw = instruction.get("instance_name") # Buscar nombre directo si x1 lo provee
        if not instance_name_raw:
             instance_name_raw = f"#CTR_INSTANCE_{instr_uid}" # Placeholder final
             print(f"Advertencia: No se encontró nombre/instancia para {instr_type_original} UID {instr_uid}. Usando placeholder '{instance_name_raw}'.")
    instance_name_scl = format_variable_name(instance_name_raw)

    # 4. Generar la llamada SCL
    param_string = ", ".join(scl_call_params)
    scl_call = f"{instance_name_scl}({param_string}); // TODO: Declarar {instance_name_scl} : {instr_type_original.upper()}; en VAR_STAT o VAR"

    # Contadores no suelen tener EN/ENO explícito en LAD, se asume siempre habilitado
    instruction["scl"] = scl_call # SCL final generado
    instruction["type"] = instr_type_original + SCL_SUFFIX

    # 4. Actualizar sympy_map para las salidas (QU, QD, CV)
    output_pins_map = {
        "CTU": ["QU", "CV"],
        "CTD": ["QD", "CV"],
        "CTUD": ["QU", "QD", "CV"]
    }
    output_pins = output_pins_map.get(instr_type_original.upper(), [])

    for pin in output_pins:
        map_key = (network_id, instr_uid, pin)
        output_scl_access = f"{instance_name_scl}.{pin.upper()}"
        if pin.upper() in ["QU", "QD"]: # These are boolean outputs
            # *** Store SymPy Symbol for boolean outputs QU/QD ***
            sympy_out_symbol = symbol_manager.get_symbol(output_scl_access)
            if sympy_out_symbol:
                sympy_map[map_key] = sympy_out_symbol # Store SYMBOL
            else:
                print(f"Error: Could not create symbol for {output_scl_access} in {instr_type_original} {instr_uid}")
                sympy_map[map_key] = None
        else:
            # For non-boolean (like CV - count value), store SCL access string
            sympy_map[map_key] = output_scl_access

    return True


# --- Processor Information Function ---
def get_processor_info():
    """Devuelve la información para los contadores CTU, CTD, CTUD."""
    return [
        {'type_name': 'ctu', 'processor_func': process_counter, 'priority': 5},
        {'type_name': 'ctd', 'processor_func': process_counter, 'priority': 5},
        {'type_name': 'ctud', 'processor_func': process_counter, 'priority': 5}
    ]