from xml.etree import cElementTree as eTree
from typing import (
    Optional,
    List,
)

from messagebus import (
    DefaultToken,
    Message,
    MessageBus,
    TokenCreator,
    TokenPriority,
)

TK_STORECFG_GETFULL = TokenCreator.create_token(
    priority=TokenPriority.low,
    message_group="13",
    number="2",
)  # 19922946


class StoreConfigRepository(object):

    def __init__(
        self,
        message_bus: MessageBus,
    ) -> None:

        self._message_bus = message_bus
        self._store_wide_config: Optional[eTree.Element] = None
        self._available_tips: Optional[List[str]] = []
        self._tip_rate: Optional[int] = None
        self._store_id: Optional[str] = None

    def get_store_wide_config(
        self,
    ) -> eTree.Element:

        if self._store_wide_config:
            return self._store_wide_config

        msg = self._message_bus.send_message(
            component="StoreWideConfig",
            message=Message(token=TK_STORECFG_GETFULL),
        )
        if msg.token == DefaultToken.TK_SYS_ACK:
            self._store_wide_config = eTree.XML(msg.data.decode())
            return self._store_wide_config

        raise RuntimeError("StoreWideConfig not found")

    def get_available_tips(
        self,
    ) -> List[str]:

        if self._available_tips:
            return self._available_tips

        store_wide_config = self.get_store_wide_config()
        tag_to_find = self._get_full_name_tag_from_store_tag(tag="key[@name='AvailableTips']/array/string")
        available_tips = store_wide_config.findall(tag_to_find)
        for tip in available_tips:
            self._available_tips.append(tip.text)

        return self._available_tips

    def get_store_id(
        self,
    ) -> str:

        if self._store_id:
            return self._store_id

        store_wide_config = self.get_store_wide_config()
        tag_to_find = self._get_full_name_tag_from_store_tag(tag="key[@name='Id']/string")
        self._store_id = store_wide_config.find(tag_to_find)

        return self._store_id.text

    def get_tip_rate(
        self,
    ) -> float:

        if self._tip_rate:
            return self._tip_rate

        store_wide_config = self.get_store_wide_config()
        tag_to_find = self._get_full_name_tag_from_store_tag(tag="key[@name='TipRate']/string")
        self._tip_rate = float(store_wide_config.find(tag_to_find).text or 10)
        return self._tip_rate

    @staticmethod
    def _get_full_name_tag_from_store_tag(
        tag: str,
    ) -> str:

        return f"group[@name='PublishedConfiguration']/group[@name='Store']/{tag}"
