# -*- coding: utf-8 -*-

import logging

from mbcontextmessagehandler import MbContextMessageBus
from messagebus import Message, DataType
from msgbus import TK_STORECFG_GET, TK_SYS_NAK
from poshelper import config_logger_with_hv_logger
from typing import (
    Optional,
    Dict,
)

from application.model.customexception import ConfigurationReaderException
from application.model.configuration import (
    Configurations,
    EndpointConfig,
)
from cfgtools import read

endpoints_config_name = ["AskTotaled", "AskPayment"]


class Configurator(object):

    def __init__(self, loader_path):
        # type: (str) -> None

        self.loader_path = loader_path
        self.reader = read(self.loader_path)
        self.configs = Configurations()

    def read_loader_configurations(self):
        # type: () -> None

        try:
            self.configs.service_name = str(self.reader.find_value("Identification.ComponentName"))
            self.configs.persistence_name = str(self._get_config("PersistenceName") or "")
            self.configs.required_services = "|".join(self._get_config("RequiredServices", array=True) or [])

            self._set_credentials_by_types()
            self.configs.endpoints.retrieve_loyalty_customer_info = str(self._get_config("EndPoints.RetrieveLoyaltyId") or "")
            self.configs.endpoints.get_benefit = str(self._get_config("EndPoints.GetBenefit") or "")
            self.configs.endpoints.burn_benefit = str(self._get_config("EndPoints.BurnBenefit") or "")
            self.configs.endpoints.lock_benefit = str(self._get_config("EndPoints.LockBenefit") or "")
            self.configs.endpoints.unlock_benefit = str(self._get_config("EndPoints.ReleaseBenefit") or "")
            self.configs.endpoints.get_totaled_message = str(self._get_config("EndPoints.Totaled") or "")
            self.configs.endpoints.payment = str(self._get_config("EndPoints.Payment") or "")

            self.configs.is_loyalty_enabled = str(self._get_config("LoyaltyEnabled") or "true").lower() == "true"
            if self.configs.is_loyalty_enabled:
                self.configs.id_type = str(self._get_config("IdentifierType") or "DOCUMENT")

            self.configs.endpoints_config = self._parse_endpoints_config()

        except Exception as ex:
            raise ConfigurationReaderException(ex)

    def _parse_endpoints_config(
        self,    # type: Configurator
    ):
        # type: (...) -> Dict[str, EndpointConfig]

        endpoints_config_group = self.reader.find_group("Loyalty.EndPointsConfigurations")
        dict_configs = {}

        if endpoints_config_group:
            for endpoint_config in endpoints_config_group.keys:
                dict_configs[endpoint_config.name] = EndpointConfig(
                    name=endpoint_config.name,
                    call_external_endpoint=endpoint_config.values[0].lower() == "true",
                )
        else:
            for endpoint_config_name in endpoints_config_name:
                dict_configs[endpoint_config_name] = EndpointConfig(name=endpoint_config_name)

        return dict_configs

    def configure_logger(self):
        # type: () -> None

        config_logger_with_hv_logger(
            loader_path=self.loader_path,
            log_name=self.configs.service_name,
            configure_root=True,
            root_level=logging.DEBUG,
        )
        self.configs.logger = logging.getLogger(self.configs.service_name)

    def get_store_id(self, message_bus):
        # type: (MbContextMessageBus) -> None

        self.configs.store_id = self._read_sw_config(message_bus, "Store.Id")

    @staticmethod
    def _read_sw_config(message_bus, key):
        # type: (MbContextMessageBus, str) -> Configurations

        message = Message(TK_STORECFG_GET, data_type=DataType.param, data=key)
        msg = message_bus.send_message("StoreWideConfig", message)
        if msg.token == TK_SYS_NAK:
            raise ConfigurationReaderException("Unable to get Store Wide Configuration: {}".format(key))
        return str(msg.data)

    def _get_config(
        self,               # type: Configurator
        key,                # type: str
        group_name="",      # type: Optional[str]
        array=False,        # type: Optional[bool]
    ):
        # type: (...) -> str

        group_replace = "." if not group_name else ".{}.".format(group_name)
        path = self.configs.service_name + group_replace + key
        return self.reader.find_values(path) if array else self.reader.find_value(path)

    def _set_credentials_by_types(
        self,   # type: Configurator
    ):
        # type: (...) -> None

        for applier_sub_type, credential in self.configs.credentials.items():
            config_value = self._get_config(
                key=applier_sub_type + ".BaseURL",
                group_name="EndPointsCredentials",
            )
            credential.base_url = str(config_value or "").strip("/")
            config_value = self._get_config(
                key=applier_sub_type + ".ApiKey",
                group_name="EndPointsCredentials",
            )
            credential.api_key = str(config_value or "")
