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

from xulcan.kernel.interfaces import StateStore
from xulcan.core.primitives import MachineID

logger = logging.getLogger("xulcan.memory.base")

class BaseStateStore(StateStore, ABC):
    """Abstract base class for State Store (Blackboard) providers."""
    
    def __init__(self, **kwargs):
        self.config = kwargs

    async def set(self, run_id: MachineID, key: str, value: Any) -> None:
        """Template method for setting a value."""
        logger.debug(f"📝 StateStore[{run_id}]: Setting key '{key}'")
        await self._set_impl(run_id, key, value)

    async def get(self, run_id: MachineID, key: str) -> Any:
        """Template method for getting a value."""
        return await self._get_impl(run_id, key)

    async def exists(self, run_id: MachineID, key: str) -> bool:
        """Template method for checking existence."""
        return await self._exists_impl(run_id, key)

    async def keys(self, run_id: MachineID) -> List[str]:
        """Template method for listing keys."""
        return await self._keys_impl(run_id)

    async def delete(self, run_id: MachineID, key: str) -> None:
        """Template method for deleting a key."""
        logger.debug(f"🗑️ StateStore[{run_id}]: Deleting key '{key}'")
        await self._delete_impl(run_id, key)

    async def clear(self, run_id: MachineID) -> None:
        """Template method for clearing the entire run's memory."""
        logger.info(f"🧹 StateStore[{run_id}]: Clearing all memory (Garbage Collection)")
        await self._clear_impl(run_id)

    # --- Abstract Implementation Methods ---
    @abstractmethod
    async def _set_impl(self, run_id: MachineID, key: str, value: Any) -> None: pass

    @abstractmethod
    async def _get_impl(self, run_id: MachineID, key: str) -> Any: pass

    @abstractmethod
    async def _exists_impl(self, run_id: MachineID, key: str) -> bool: pass

    @abstractmethod
    async def _keys_impl(self, run_id: MachineID) -> List[str]: pass

    @abstractmethod
    async def _delete_impl(self, run_id: MachineID, key: str) -> None: pass

    @abstractmethod
    async def _clear_impl(self, run_id: MachineID) -> None: pass