# app/src/market_data/acquisition/registry.py

from __future__ import annotations

from src.market_data.acquisition.exceptions import (
    CandleFeedRegistryError,
    InstrumentFeedRegistryError,
    QuoteFeedRegistryError,
)
from src.market_data.acquisition.protocol import (
    CandlesFeedProtocol,
    InstrumentFeedProtocol,
    QuoteFeedProtocol,
)


# Реестр доступных Feed справочника инструментов.
class InstrumentFeedRegistry:
    def __init__(self) -> None:
        self._feeds: dict[str, InstrumentFeedProtocol] = {}

    def register(
        self,
        source_name: str,
        feed: InstrumentFeedProtocol,
    ) -> None:
        """
        Зарегистрировать Instrument Feed для указанного источника.

        Повторная регистрация того же имени запрещена, чтобы исключить
        неявную замену production-зависимости.
        """

        normalized_source_name = self._normalize_source_name(source_name)

        if not isinstance(feed, InstrumentFeedProtocol):
            raise InstrumentFeedRegistryError(
                f"Объект для источника '{normalized_source_name}' "
                "не соответствует InstrumentFeedProtocol."
            )

        if normalized_source_name in self._feeds:
            raise InstrumentFeedRegistryError(
                f"Instrument Feed для источника "
                f"'{normalized_source_name}' уже зарегистрирован."
            )

        self._feeds[normalized_source_name] = feed

    def get(
        self,
        source_name: str,
    ) -> InstrumentFeedProtocol:
        """Вернуть зарегистрированный Instrument Feed по имени источника."""

        normalized_source_name = self._normalize_source_name(source_name)

        feed = self._feeds.get(normalized_source_name)

        if feed is None:
            raise InstrumentFeedRegistryError(
                f"Instrument Feed для источника "
                f"'{normalized_source_name}' не зарегистрирован."
            )

        return feed

    def _normalize_source_name(
        self,
        source_name: str,
    ) -> str:
        normalized_source_name = source_name.strip()

        if not normalized_source_name:
            raise InstrumentFeedRegistryError(
                "Имя источника Instrument Feed не должно быть пустым."
            )

        return normalized_source_name


# Реестр доступных потоков текущих котировок.
class QuoteFeedRegistry:
    def __init__(self) -> None:
        self._feeds: dict[str, QuoteFeedProtocol] = {}

    def register(
        self,
        source_name: str,
        feed: QuoteFeedProtocol,
    ) -> None:
        """
        Зарегистрировать Quotes Feed для указанного источника.

        Повторная регистрация того же имени запрещена, чтобы исключить
        неявную замену production-зависимости.
        """

        normalized_source_name = self._normalize_source_name(source_name)

        if not isinstance(feed, QuoteFeedProtocol):
            raise QuoteFeedRegistryError(
                f"Объект для источника '{normalized_source_name}' "
                "не соответствует QuoteFeedProtocol."
            )

        if normalized_source_name in self._feeds:
            raise QuoteFeedRegistryError(
                f"Quotes Feed для источника "
                f"'{normalized_source_name}' уже зарегистрирован."
            )

        self._feeds[normalized_source_name] = feed

    def get(
        self,
        source_name: str,
    ) -> QuoteFeedProtocol:
        """Вернуть зарегистрированный Quotes Feed по имени источника."""

        normalized_source_name = self._normalize_source_name(source_name)

        feed = self._feeds.get(normalized_source_name)

        if feed is None:
            raise QuoteFeedRegistryError(
                f"Quotes Feed для источника "
                f"'{normalized_source_name}' не зарегистрирован."
            )

        return feed

    def _normalize_source_name(
        self,
        source_name: str,
    ) -> str:
        normalized_source_name = source_name.strip()

        if not normalized_source_name:
            raise QuoteFeedRegistryError(
                "Имя источника Quotes Feed не должно быть пустым."
            )

        return normalized_source_name


# Реестр доступных потоков рыночных свечей.
class CandlesFeedRegistry:
    def __init__(self) -> None:
        self._feeds: dict[str, CandlesFeedProtocol] = {}

    def register(
        self,
        source_name: str,
        feed: CandlesFeedProtocol,
    ) -> None:
        """
        Зарегистрировать Candles Feed для указанного источника.

        Повторная регистрация того же имени запрещена, чтобы исключить
        неявную замену production-зависимости.
        """

        normalized_source_name = self._normalize_source_name(source_name)

        if not isinstance(feed, CandlesFeedProtocol):
            raise CandleFeedRegistryError(
                f"Объект для источника '{normalized_source_name}' "
                "не соответствует CandlesFeedProtocol."
            )

        if normalized_source_name in self._feeds:
            raise CandleFeedRegistryError(
                f"Candles Feed для источника "
                f"'{normalized_source_name}' уже зарегистрирован."
            )

        self._feeds[normalized_source_name] = feed

    def get(
        self,
        source_name: str,
    ) -> CandlesFeedProtocol:
        """Вернуть зарегистрированный Candles Feed по имени источника."""

        normalized_source_name = self._normalize_source_name(source_name)

        feed = self._feeds.get(normalized_source_name)

        if feed is None:
            raise CandleFeedRegistryError(
                f"Candles Feed для источника "
                f"'{normalized_source_name}' не зарегистрирован."
            )

        return feed

    def _normalize_source_name(
        self,
        source_name: str,
    ) -> str:
        normalized_source_name = source_name.strip()

        if not normalized_source_name:
            raise CandleFeedRegistryError(
                "Имя источника Candles Feed не должно быть пустым."
            )

        return normalized_source_name
