import copy
import logging
from typing import Optional, List, Dict, Any

import safe_radix32

from clarabot_nano.common.config.constants import NanoServeAPI
from clarabot_nano.common.config.extract.base import AbstractExtractedConfig

logger = logging.getLogger(__name__)


class ServesExtractedConfig(AbstractExtractedConfig):
    """
    Collect an inverse map of the rooms the system's resources shall be bound to. (the rooms this Nano wishes to serve)
    NOTE: Resources that are not mapped to a single valid room are filtered out!
    """

    def __init__(self, config):
        self.deny_anonymous: bool = config["remote"]["deny_anonymous"]
        self.rooms: Dict[int, Dict[int, dict]] = dict()  # room-id -> {api_flag: resource}
        self._init_room_serves(NanoServeAPI.DRIVE_V2, config["remote"]["drives"])

    def _init_room_serves(self, api_flag: int, resources: List[dict]):
        resources = copy.deepcopy(resources)
        for resource in resources:
            for packed_room_id in resource.pop("rooms", []):
                try:
                    room_id = safe_radix32.decode(packed_room_id)
                except (UnicodeEncodeError, OverflowError):
                    logger.warning("Ignoring invalid room-id: %s", packed_room_id)
                    continue
                room_apis = self.rooms.get(room_id)
                if not room_apis:
                    self.rooms[room_id] = {api_flag: resource}
                elif api_flag not in room_apis:
                    room_apis[api_flag] = resource

    def get_serves(self) -> List[Dict[str, Any]]:
        serves = []
        for room_id, room_apis in self.rooms.items():
            api = 0
            for api_flag in room_apis.keys():
                api |= api_flag
            if api:
                serves.append({"id": room_id, "api": api})
        return serves

    def _matches(self, other):
        return self.rooms == other.rooms and self.deny_anonymous == other.deny_anonymous
