# processors/symbol_manager.py
import sympy
import re

class SymbolManager:
    def __init__(self):
        # plc_name -> py_id (e.g., '"DB".Var' -> 'v0_')
        self.plc_to_py_id = {}
        # py_id -> Symbol object (e.g., 'v0_' -> sympy.Symbol('v0_'))
        self.py_id_to_symbol = {}
        # py_id -> plc_name (e.g., 'v0_' -> '"DB".Var') - Inverse mapping
        self.py_id_to_plc = {}
        self.counter = 0
        # Pre-define common keywords/constants to avoid mapping them
        self.reserved_names = {"TRUE", "FALSE"} # Add others if needed

    def _generate_py_id(self):
        py_id = f"v{self.counter}_"
        self.counter += 1
        # Extremely unlikely collision, but check anyway
        while py_id in self.py_id_to_symbol:
             py_id = f"v{self.counter}_"
             self.counter += 1
        return py_id

    def get_symbol(self, plc_var_name):
        """Gets/Creates a SymPy Symbol for a PLC variable name."""
        if plc_var_name is None:
            print("Warning: Attempted to get symbol for None PLC name.")
            return None # Or handle error appropriately
        if plc_var_name.upper() in self.reserved_names:
             print(f"Warning: Attempted to create symbol for reserved name: {plc_var_name}")
             return None # Or handle differently (e.g., return sympy.true/false?)

        if plc_var_name not in self.plc_to_py_id:
            py_id = self._generate_py_id()
            self.plc_to_py_id[plc_var_name] = py_id
            self.py_id_to_plc[py_id] = plc_var_name
            self.py_id_to_symbol[py_id] = sympy.symbols(py_id)
            # print(f"DEBUG SymbolManager: Created {py_id} -> {plc_var_name}") # Debug
        else:
            py_id = self.plc_to_py_id[plc_var_name]

        return self.py_id_to_symbol.get(py_id)

    def get_plc_name(self, py_id):
        """Gets the original PLC name from a py_id."""
        return self.py_id_to_plc.get(py_id)

    def get_inverse_map(self):
        """Returns the map needed for postprocessing (py_id -> plc_name)."""
        return self.py_id_to_plc.copy()

# Helper function to extract PLC variable name from JSON operand info
def extract_plc_variable_name(operand_info):
     if operand_info and operand_info.get("type") == "variable":
         return operand_info.get("name")
     return None # Not a variable or info missing