from abc import ABC, abstractmethod

from p4pillon.pvrecipe import BasePVRecipe
from p4pillon.server.raw import SharedPV


class BaseSimpleServer(ABC):
    """
    Creates PVs and manages their lifetimes
    """

    @abstractmethod
    def __init__(self, prefix: str = "") -> None:
        """
        Initialize the SimpleServer instance.

        :param prefix: The prefix to be added to the PVs (Process Variables) of the server e.g. DEV: Defaults to "".
        """
        # the prefix determines the prefix of the PVs to be added to the server e.g. DEV:
        self.prefix: str = prefix  #: The prefix to be prepended to the PVs generated by this server.
        self._pvs: dict[str, SharedPV] = {}

    @abstractmethod
    def add_pv(self, pv_name: str, pv_recipe: BasePVRecipe) -> SharedPV:
        """
        Add a PV to the server

        :param pv_name: The name of the PV to be added.
        :param pv_recipe: The recipe with instructions for creating the PV.
        :return: The created PV.
        """

    @abstractmethod
    def remove_pv(self, pv_name: str) -> None:
        """
        Remove a PV from the server

        :param pv_name: The name of the PV to be removed.
        :raises KeyError: If the PV is not found in the list managed by the server.
        """

    @property
    def pvlist(self) -> list[str]:
        """The PVs managed by the server"""
        return list(self._pvs.keys())

    def __getitem__(self, pv_name: str) -> SharedPV | None:
        """Return one of the PVs managed by the server given its name"""
        if not pv_name.startswith(self.prefix):
            pv_name = self.prefix + pv_name
        return self._pvs.get(pv_name)
