from typing import (
    List,
    Dict,
)

from devicemanager.interactor.dto import DeviceStatusDto
from devicemanager.model import (
    DeviceConfig,
    DeviceStatus,
)
from devicemanager.repository import DeviceManagerRepository


class GetDevicesService(object):
    def __init__(
        self,
        repository,         # type: DeviceManagerRepository
        device_configs,     # type: List[DeviceConfig]
    ):
        # type: (...) -> None

        self.repository = repository
        self.available_names = []
        self.available_device_names = {}
        for config in device_configs:
            device_names_to_process = [config.default_device] + config.fallback_devices
            for device_name in device_names_to_process:
                if device_name not in self.available_device_names:
                    self.available_device_names[device_name] = True
                    self.available_names.append(device_name)

    def get_devices(
        self,   # type: GetDevicesService
    ):
        # type: (...) -> List[DeviceStatusDto]

        devices = self.repository.get_devices_with_last_history(device_names=self.available_names)
        processed_devices = dict(self.available_device_names)
        ret = self._create_in_database_devices(
            devices=devices,
            processed_devices=processed_devices,
        )
        ret.extend(self._create_configured_but_not_in_database(processed_devices=processed_devices))
        return sorted(ret, key=lambda x: x.name)

    @staticmethod
    def _create_in_database_devices(
        devices,            # type: List[DeviceStatus]
        processed_devices,  # type: Dict[str, bool]
    ):
        # type: (...) -> List[DeviceStatusDto]

        ret = []
        for device in devices:
            if device.device_name in processed_devices:
                ret.append(
                    DeviceStatusDto(
                        type="printer",
                        name=device.device_name,
                        last_update=device.history[0].timestamp,
                        last_update_operator=device.history[0].operator,
                        enabled=device.enabled,
                    )
                )
                del processed_devices[device.device_name]
        return ret

    @staticmethod
    def _create_configured_but_not_in_database(
        processed_devices
    ):
        # type: (...) -> List[DeviceStatusDto]

        ret = []
        for key in list(processed_devices.keys()):
            ret.append(
                DeviceStatusDto(
                    type="printer",
                    name=key,
                    last_update=None,
                    last_update_operator=None,
                    enabled=True,
                )
            )
        return ret
