import logging
from abc import ABC, abstractmethod
from typing import Any, Dict

from langchain_core.runnables import RunnableConfig

from baicai_base.utils.setups import setup_logging


class BaseNode(ABC):
    """
    Abstract Base Class for nodes that perform operations involving an LLM, code interpreter,
    and logger. Provides a structure for nodes that manipulate the graph state.

    Attributes:
        llm: An instance of the LLM for code generation. Defaults to None.
        logger (logging.Logger): Logger for logging messages. Defaults to None.
        feedbacks: The feedback to be used for code generation.
        solution: The solution generated by the node.
        runnable: The runnable instance associated with the node.
        runnables: A dictionary of runnables associated with the node.
        name (str): Name of the node. Defaults to an empty string.
        graph_name (str): Name of the graph. Defaults to an empty string.
    """

    def __init__(self, llm: Any = None, logger: logging.Logger = None, name: str = "", graph_name: str = "") -> None:
        """
        Initialize the BaseNode with an LLM, a logger, name, and graph name.
        """
        self.llm = llm
        setup_logging()
        self.logger = logger or logging.getLogger(__name__)

        self.feedbacks = None  # The feedback to be used for code generation.
        self.solution = None
        self.runnable = None
        self.runnables = {}
        self.name = name.lower()
        self.graph_name = graph_name.lower()

    @abstractmethod
    def __call__(self, state: Dict[str, Any], config: RunnableConfig):
        """
        Execute the node's logic.

        Args:
            state (Dict[str, Any]): The current state of the baseline process.
            config (RunnableConfig): Configuration details for the node.

        Returns:
            Dict[str, Any]: Updated state after execution.
        """
        pass

    def get_state(self, state, key, default_value):
        """
        Get the state of the node.

        Args:
            state (dict): The current state of the node.
            key (str): The key to get the state from.
            default_value (str): The default value to return if the key is not found.

        Returns:
            str: The state of the node.
        """
        if key not in state or not state[key]:
            self.logger.warning(f"<font color='red'>Using default value or input parameter for {key}</font>")
            return default_value
        else:
            return state[key]
