import logging

from cfgtools import (
    read,
    Group,
)
from typing import (
    Dict,
    List,
    Tuple,
)

from devicemanager.model import (
    Configs,
    DeviceConfig,
)

logger = logging.getLogger(__name__)


class Configurator(object):

    @staticmethod
    def read_loader_configs(
        loader_path,  # type: str
    ):
        # type: (...) -> Configs

        reader = read(loader_path)
        main_group = reader.find_group("DeviceManager")

        device_configs = Configurator._parse_device_configs(
            main_group=main_group,
            config_names=["POS", "KDS"]
        )
        brand_config = Configurator._get_brands_configs(
            main_group=main_group,
        )

        return Configs(
            component_name=reader.find_value("Identification.ComponentName"),
            required_services="",
            persistence_name=reader.find_value("DeviceManager.PersistenceName").encode("utf-8"),
            sector_config=Configurator._get_sectors(main_group=main_group),
            device_configs=device_configs,
            brand_config=brand_config,
        )

    @staticmethod
    def _get_sectors(
        main_group,  # type: Group
    ):
        # type: (...) -> Dict[str, Dict[str, Tuple[str, Dict[int, int]]]]

        sectors_config = {}
        sectors = main_group.find_group("Sectors")
        for sector in sectors.groups:
            sector_name = sector.name.upper()
            if sector_name not in sectors_config:
                sectors_config[sector_name] = {}

            excluded_pos = {}
            for key in sector.keys:
                key_name = key.name.upper()
                if key_name == "EXCLUDEDPOS":
                    for pos_number in key.values:
                        excluded_pos[int(pos_number)] = int(pos_number)
                else:
                    device_type = key_name
                    device_name = key.value()
                    if device_type in sectors_config[sector_name]:
                        logger.info("Device manager sector loader key duplicated - {}{}".format(sector.name, key.name))
                    sectors_config[sector_name][device_type] = (device_name, excluded_pos)

            if not sectors_config[sector_name]:
                del sectors_config[sector_name]

        return sectors_config

    @staticmethod
    def _parse_device_configs(
        main_group,    # type: Group
        config_names,  # type: List[str]
    ):
        # type: (...) -> List[DeviceConfig]

        device_configs = []
        for config_name in config_names:
            device_groups = main_group.find_group(config_name)
            if not device_groups:
                continue

            for device_group in device_groups.groups:
                group_name = device_group.name.upper()
                printer_group = device_group.find_group("printer")
                if not printer_group:
                    continue

                default_device = printer_group.find_value("Default")
                fallback_devices = printer_group.find_values("Fallback") or []

                device_configs.append(
                    DeviceConfig(
                        requester_type=group_name[:3],
                        requester_id=int(group_name[3:]),
                        default_device=default_device,
                        fallback_devices=fallback_devices,
                    )
                )
        return device_configs

    @staticmethod
    def _get_brands_configs(
        main_group,    # type: Group
    ):
        # type: (...) -> Dict[str, Dict[str, str]]

        brand_config = {}
        brands = main_group.find_group("Brands")
        if not brands:
            return brand_config

        for brand in brands.groups:
            if not brand.keys:
                continue

            brand_name = brand.name.upper()
            for brand_key in brand.keys:
                brand_config.update(
                    {
                        brand_name: {
                            brand_key.name.upper(): brand_key.value()
                        }
                    }

                )

        return brand_config
